Merge "MediaCodec: report message from CodecErrorLog" am: c33f81fff5

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/2407712

Change-Id: I967ae6481da07bdf64edd07d6791116de4d9cf4d
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Treehugger Robot
2023-04-05 20:23:50 +00:00
committed by Automerger Merge Worker
2 changed files with 175 additions and 90 deletions

View File

@@ -43,6 +43,8 @@
#include <android_runtime/android_hardware_HardwareBuffer.h> #include <android_runtime/android_hardware_HardwareBuffer.h>
#include <android-base/stringprintf.h>
#include <binder/MemoryDealer.h> #include <binder/MemoryDealer.h>
#include <cutils/compiler.h> #include <cutils/compiler.h>
@@ -1099,7 +1101,8 @@ void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
ALOGE("Could not create MediaCodec.BufferInfo."); ALOGE("Could not create MediaCodec.BufferInfo.");
env->ExceptionClear(); env->ExceptionClear();
} }
jniThrowException(env, "java/lang/IllegalStateException", NULL); jniThrowException(env, "java/lang/IllegalStateException",
"Fatal error: could not create MediaCodec.BufferInfo object");
return; return;
} }
@@ -1121,7 +1124,8 @@ void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
ALOGE("Could not create CodecException object."); ALOGE("Could not create CodecException object.");
env->ExceptionClear(); env->ExceptionClear();
} }
jniThrowException(env, "java/lang/IllegalStateException", NULL); jniThrowException(env, "java/lang/IllegalStateException",
"Fatal error: could not create CodecException object");
return; return;
} }
@@ -1134,7 +1138,9 @@ void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
CHECK(msg->findMessage("format", &format)); CHECK(msg->findMessage("format", &format));
if (OK != ConvertMessageToMap(env, format, &obj)) { 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; return;
} }
@@ -1166,7 +1172,8 @@ void JMediaCodec::handleFirstTunnelFrameReadyNotification(const sp<AMessage> &ms
status_t err = ConvertMessageToMap(env, data, &obj); status_t err = ConvertMessageToMap(env, data, &obj);
if (err != OK) { 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; return;
} }
@@ -1187,7 +1194,8 @@ void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
status_t err = ConvertMessageToMap(env, data, &obj); status_t err = ConvertMessageToMap(env, data, &obj);
if (err != OK) { 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; return;
} }
@@ -1198,6 +1206,18 @@ void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
env->DeleteLocalRef(obj); 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) { void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) { switch (msg->what()) {
case kWhatCallbackNotify: case kWhatCallbackNotify:
@@ -1347,9 +1367,17 @@ static void throwCryptoException(JNIEnv *env, status_t err, const char *msg,
env->Throw(exception); 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( static jint throwExceptionAsNecessary(
JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL, 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) { switch (err) {
case OK: case OK:
return 0; return 0;
@@ -1364,23 +1392,38 @@ static jint throwExceptionAsNecessary(
return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED; return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
case INVALID_OPERATION: case INVALID_OPERATION:
jniThrowException(env, "java/lang/IllegalStateException", msg); jniThrowException(
env, "java/lang/IllegalStateException",
GetExceptionMessage(codec, msg).c_str());
return 0; return 0;
case BAD_VALUE: case BAD_VALUE:
jniThrowException(env, "java/lang/IllegalArgumentException", msg); jniThrowException(
env, "java/lang/IllegalArgumentException",
GetExceptionMessage(codec, msg).c_str());
return 0; return 0;
default: default:
if (isCryptoError(err)) { if (isCryptoError(err)) {
throwCryptoException(env, err, msg, crypto); throwCryptoException(
env, err,
GetExceptionMessage(codec, msg).c_str(),
crypto);
return 0; return 0;
} }
throwCodecException(env, err, actionCode, msg); throwCodecException(
env, err, actionCode,
GetExceptionMessage(codec, msg).c_str());
return 0; 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( static void android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener(
JNIEnv *env, JNIEnv *env,
jobject thiz, jobject thiz,
@@ -1388,13 +1431,13 @@ static void android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListene
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
status_t err = codec->enableOnFirstTunnelFrameReadyListener(enabled); status_t err = codec->enableOnFirstTunnelFrameReadyListener(enabled);
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
} }
static void android_media_MediaCodec_native_enableOnFrameRenderedListener( static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
@@ -1404,13 +1447,13 @@ static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
status_t err = codec->enableOnFrameRenderedListener(enabled); status_t err = codec->enableOnFrameRenderedListener(enabled);
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
} }
static void android_media_MediaCodec_native_setCallback( static void android_media_MediaCodec_native_setCallback(
@@ -1420,13 +1463,13 @@ static void android_media_MediaCodec_native_setCallback(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
status_t err = codec->setCallback(cb); status_t err = codec->setCallback(cb);
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
} }
static void android_media_MediaCodec_native_configure( static void android_media_MediaCodec_native_configure(
@@ -1440,7 +1483,7 @@ static void android_media_MediaCodec_native_configure(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
@@ -1478,7 +1521,7 @@ static void android_media_MediaCodec_native_configure(
err = codec->configure(format, bufferProducer, crypto, descrambler, flags); err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
} }
static void android_media_MediaCodec_native_setSurface( static void android_media_MediaCodec_native_setSurface(
@@ -1488,7 +1531,7 @@ static void android_media_MediaCodec_native_setSurface(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
@@ -1507,7 +1550,7 @@ static void android_media_MediaCodec_native_setSurface(
} }
status_t err = codec->setSurface(bufferProducer); status_t err = codec->setSurface(bufferProducer);
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
} }
sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface( sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
@@ -1611,7 +1654,7 @@ static void android_media_MediaCodec_setInputSurface(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
@@ -1625,7 +1668,7 @@ static void android_media_MediaCodec_setInputSurface(
} }
status_t err = codec->setInputSurface(persistentSurface); status_t err = codec->setInputSurface(persistentSurface);
if (err != NO_ERROR) { if (err != NO_ERROR) {
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
} }
} }
@@ -1635,7 +1678,7 @@ static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL; return NULL;
} }
@@ -1643,7 +1686,7 @@ static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
sp<IGraphicBufferProducer> bufferProducer; sp<IGraphicBufferProducer> bufferProducer;
status_t err = codec->createInputSurface(&bufferProducer); status_t err = codec->createInputSurface(&bufferProducer);
if (err != NO_ERROR) { if (err != NO_ERROR) {
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
return NULL; return NULL;
} }
@@ -1658,13 +1701,13 @@ static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
status_t err = codec->start(); 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) { static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
@@ -1673,13 +1716,13 @@ static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
status_t err = codec->stop(); status_t err = codec->stop();
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
} }
static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) { static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
@@ -1688,7 +1731,7 @@ static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
@@ -1701,7 +1744,7 @@ static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
// trigger an IllegalStateException. // trigger an IllegalStateException.
err = UNKNOWN_ERROR; err = UNKNOWN_ERROR;
} }
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
} }
static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) { static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
@@ -1710,13 +1753,13 @@ static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
status_t err = codec->flush(); status_t err = codec->flush();
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
} }
static void android_media_MediaCodec_queueInputBuffer( static void android_media_MediaCodec_queueInputBuffer(
@@ -1732,7 +1775,7 @@ static void android_media_MediaCodec_queueInputBuffer(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
@@ -1742,7 +1785,8 @@ static void android_media_MediaCodec_queueInputBuffer(
index, offset, size, timestampUs, flags, &errorDetailMsg); index, offset, size, timestampUs, flags, &errorDetailMsg);
throwExceptionAsNecessary( 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 { struct NativeCryptoInfo {
@@ -1766,7 +1810,9 @@ struct NativeCryptoInfo {
} else if (jmode == gCryptoModes.AesCbc) { } else if (jmode == gCryptoModes.AesCbc) {
mMode = CryptoPlugin::kMode_AES_CBC; mMode = CryptoPlugin::kMode_AES_CBC;
} else { } else {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(
env, INVALID_OPERATION, ACTION_CODE_FATAL,
base::StringPrintf("unrecognized crypto mode: %d", jmode).c_str());
return; return;
} }
@@ -1902,7 +1948,7 @@ static void android_media_MediaCodec_queueSecureInputBuffer(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
@@ -1932,7 +1978,9 @@ static void android_media_MediaCodec_queueSecureInputBuffer(
} else if (jmode == gCryptoModes.AesCbc) { } else if (jmode == gCryptoModes.AesCbc) {
mode = CryptoPlugin::kMode_AES_CBC; mode = CryptoPlugin::kMode_AES_CBC;
} else { } else {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(
env, INVALID_OPERATION, ACTION_CODE_FATAL,
base::StringPrintf("Unrecognized crypto mode: %d", jmode).c_str());
return; return;
} }
@@ -2051,8 +2099,8 @@ static void android_media_MediaCodec_queueSecureInputBuffer(
subSamples = NULL; subSamples = NULL;
throwExceptionAsNecessary( throwExceptionAsNecessary(
env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str(), env, err, ACTION_CODE_FATAL,
codec->getCrypto()); codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
} }
static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) { static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
@@ -2394,14 +2442,16 @@ static void android_media_MediaCodec_native_queueLinearBlock(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == nullptr || codec->initCheck() != OK) { if (codec == nullptr || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
sp<AMessage> tunings; sp<AMessage> tunings;
status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings); status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
if (err != OK) { if (err != OK) {
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(
env, err, ACTION_CODE_FATAL,
"error occurred while converting tunings from Java to native");
return; return;
} }
@@ -2421,15 +2471,23 @@ static void android_media_MediaCodec_native_queueLinearBlock(
} }
env->MonitorExit(lock.get()); env->MonitorExit(lock.get());
} else { } else {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(
env, INVALID_OPERATION, ACTION_CODE_FATAL,
"Failed to grab lock for a LinearBlock object");
return; return;
} }
AString errorDetailMsg; AString errorDetailMsg;
if (codec->hasCryptoOrDescrambler()) { if (codec->hasCryptoOrDescrambler()) {
if (!memory) { if (!memory) {
// It means there was an unexpected failure in extractMemoryFromContext above
ALOGI("queueLinearBlock: no ashmem memory for encrypted content"); 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; return;
} }
auto cryptoInfo = auto cryptoInfo =
@@ -2453,14 +2511,22 @@ static void android_media_MediaCodec_native_queueLinearBlock(
ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err); ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
} else { } else {
if (!buffer) { if (!buffer) {
// It means there was an unexpected failure in extractBufferFromContext above
ALOGI("queueLinearBlock: no C2Buffer found"); 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; return;
} }
err = codec->queueBuffer( err = codec->queueBuffer(
index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg); 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( static void android_media_MediaCodec_native_queueHardwareBuffer(
@@ -2471,14 +2537,16 @@ static void android_media_MediaCodec_native_queueHardwareBuffer(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
sp<AMessage> tunings; sp<AMessage> tunings;
status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings); status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
if (err != OK) { if (err != OK) {
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(
env, err, ACTION_CODE_FATAL,
"error occurred while converting tunings from Java to native");
return; return;
} }
@@ -2503,7 +2571,9 @@ static void android_media_MediaCodec_native_queueHardwareBuffer(
ALOGW("Failed to wrap AHardwareBuffer into C2GraphicAllocation"); ALOGW("Failed to wrap AHardwareBuffer into C2GraphicAllocation");
native_handle_close(handle); native_handle_close(handle);
native_handle_delete(handle); native_handle_delete(handle);
throwExceptionAsNecessary(env, BAD_VALUE); throwExceptionAsNecessary(
env, BAD_VALUE, ACTION_CODE_FATAL,
"HardwareBuffer not recognized");
return; return;
} }
std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc); std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
@@ -2512,7 +2582,9 @@ static void android_media_MediaCodec_native_queueHardwareBuffer(
AString errorDetailMsg; AString errorDetailMsg;
err = codec->queueBuffer( err = codec->queueBuffer(
index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg); 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( static void android_media_MediaCodec_native_getOutputFrame(
@@ -2522,13 +2594,13 @@ static void android_media_MediaCodec_native_getOutputFrame(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
status_t err = codec->getOutputFrame(env, frame, index); status_t err = codec->getOutputFrame(env, frame, index);
if (err != OK) { if (err != OK) {
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
} }
} }
@@ -2539,7 +2611,7 @@ static jint android_media_MediaCodec_dequeueInputBuffer(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return -1; return -1;
} }
@@ -2550,7 +2622,7 @@ static jint android_media_MediaCodec_dequeueInputBuffer(
return (jint) index; return (jint) index;
} }
return throwExceptionAsNecessary(env, err); return throwExceptionAsNecessary(env, err, codec);
} }
static jint android_media_MediaCodec_dequeueOutputBuffer( static jint android_media_MediaCodec_dequeueOutputBuffer(
@@ -2560,7 +2632,7 @@ static jint android_media_MediaCodec_dequeueOutputBuffer(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return 0; return 0;
} }
@@ -2572,7 +2644,7 @@ static jint android_media_MediaCodec_dequeueOutputBuffer(
return (jint) index; return (jint) index;
} }
return throwExceptionAsNecessary(env, err); return throwExceptionAsNecessary(env, err, codec);
} }
static void android_media_MediaCodec_releaseOutputBuffer( static void android_media_MediaCodec_releaseOutputBuffer(
@@ -2583,13 +2655,13 @@ static void android_media_MediaCodec_releaseOutputBuffer(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs); status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
} }
static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env, static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
@@ -2598,13 +2670,13 @@ static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
status_t err = codec->signalEndOfInputStream(); status_t err = codec->signalEndOfInputStream();
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
} }
static jobject android_media_MediaCodec_getFormatNative( static jobject android_media_MediaCodec_getFormatNative(
@@ -2614,7 +2686,7 @@ static jobject android_media_MediaCodec_getFormatNative(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL; return NULL;
} }
@@ -2625,7 +2697,7 @@ static jobject android_media_MediaCodec_getFormatNative(
return format; return format;
} }
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
return NULL; return NULL;
} }
@@ -2637,7 +2709,7 @@ static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL; return NULL;
} }
@@ -2648,7 +2720,7 @@ static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
return format; return format;
} }
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
return NULL; return NULL;
} }
@@ -2660,7 +2732,7 @@ static jobjectArray android_media_MediaCodec_getBuffers(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL; return NULL;
} }
@@ -2673,7 +2745,7 @@ static jobjectArray android_media_MediaCodec_getBuffers(
// if we're out of memory, an exception was already thrown // if we're out of memory, an exception was already thrown
if (err != NO_MEMORY) { if (err != NO_MEMORY) {
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
} }
return NULL; return NULL;
@@ -2686,7 +2758,7 @@ static jobject android_media_MediaCodec_getBuffer(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL; return NULL;
} }
@@ -2699,7 +2771,7 @@ static jobject android_media_MediaCodec_getBuffer(
// if we're out of memory, an exception was already thrown // if we're out of memory, an exception was already thrown
if (err != NO_MEMORY) { if (err != NO_MEMORY) {
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
} }
return NULL; return NULL;
@@ -2712,7 +2784,7 @@ static jobject android_media_MediaCodec_getImage(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL; return NULL;
} }
@@ -2725,7 +2797,7 @@ static jobject android_media_MediaCodec_getImage(
// if we're out of memory, an exception was already thrown // if we're out of memory, an exception was already thrown
if (err != NO_MEMORY) { if (err != NO_MEMORY) {
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
} }
return NULL; return NULL;
@@ -2738,7 +2810,7 @@ static jobject android_media_MediaCodec_getName(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL; return NULL;
} }
@@ -2749,7 +2821,7 @@ static jobject android_media_MediaCodec_getName(
return name; return name;
} }
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
return NULL; return NULL;
} }
@@ -2761,7 +2833,7 @@ static jobject android_media_MediaCodec_getOwnCodecInfo(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL; return NULL;
} }
@@ -2772,7 +2844,7 @@ static jobject android_media_MediaCodec_getOwnCodecInfo(
return codecInfoObj; return codecInfoObj;
} }
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
return NULL; return NULL;
} }
@@ -2784,7 +2856,8 @@ android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
jniThrowException(env, "java/lang/IllegalStateException", NULL); jniThrowException(env, "java/lang/IllegalStateException",
GetExceptionMessage(codec, NULL).c_str());
return 0; return 0;
} }
@@ -2813,7 +2886,7 @@ static void android_media_MediaCodec_setParameters(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
@@ -2824,7 +2897,7 @@ static void android_media_MediaCodec_setParameters(
err = codec->setParameters(params); err = codec->setParameters(params);
} }
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err, codec);
} }
static void android_media_MediaCodec_setVideoScalingMode( static void android_media_MediaCodec_setVideoScalingMode(
@@ -2832,13 +2905,14 @@ static void android_media_MediaCodec_setVideoScalingMode(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
&& mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { && 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; return;
} }
@@ -2850,7 +2924,7 @@ static void android_media_MediaCodec_setAudioPresentation(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
@@ -2862,14 +2936,14 @@ static jobject android_media_MediaCodec_getSupportedVendorParameters(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL; return NULL;
} }
jobject ret = NULL; jobject ret = NULL;
status_t status = codec->querySupportedVendorParameters(env, &ret); status_t status = codec->querySupportedVendorParameters(env, &ret);
if (status != OK) { if (status != OK) {
throwExceptionAsNecessary(env, status); throwExceptionAsNecessary(env, status, codec);
} }
return ret; return ret;
@@ -2880,7 +2954,7 @@ static jobject android_media_MediaCodec_getParameterDescriptor(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL; return NULL;
} }
@@ -2897,13 +2971,13 @@ static void android_media_MediaCodec_subscribeToVendorParameters(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
status_t status = codec->subscribeToVendorParameters(env, names); status_t status = codec->subscribeToVendorParameters(env, names);
if (status != OK) { if (status != OK) {
throwExceptionAsNecessary(env, status); throwExceptionAsNecessary(env, status, codec);
} }
return; return;
} }
@@ -2913,13 +2987,13 @@ static void android_media_MediaCodec_unsubscribeFromVendorParameters(
sp<JMediaCodec> codec = getMediaCodec(env, thiz); sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) { if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return; return;
} }
status_t status = codec->unsubscribeFromVendorParameters(env, names); status_t status = codec->unsubscribeFromVendorParameters(env, names);
if (status != OK) { if (status != OK) {
throwExceptionAsNecessary(env, status); throwExceptionAsNecessary(env, status, codec);
} }
return; return;
} }
@@ -3310,11 +3384,15 @@ static jobject android_media_MediaCodec_LinearBlock_native_map(
if (!context->mReadonlyMapping) { if (!context->mReadonlyMapping) {
const C2BufferData data = buffer->data(); const C2BufferData data = buffer->data();
if (data.type() != C2BufferData::LINEAR) { 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; return nullptr;
} }
if (data.linearBlocks().size() != 1u) { 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; return nullptr;
} }
C2ConstLinearBlock block = data.linearBlocks().front(); C2ConstLinearBlock block = data.linearBlocks().front();
@@ -3362,7 +3440,9 @@ static jobject android_media_MediaCodec_LinearBlock_native_map(
false, // readOnly false, // readOnly
true /* clearBuffer */); true /* clearBuffer */);
} }
throwExceptionAsNecessary(env, INVALID_OPERATION); throwExceptionAsNecessary(
env, INVALID_OPERATION, ACTION_CODE_FATAL,
"Underlying buffer is empty");
return nullptr; return nullptr;
} }
@@ -3385,7 +3465,9 @@ static void PopulateNamesVector(
} }
const char *cstr = env->GetStringUTFChars(jstr, nullptr); const char *cstr = env->GetStringUTFChars(jstr, nullptr);
if (cstr == nullptr) { if (cstr == nullptr) {
throwExceptionAsNecessary(env, BAD_VALUE); throwExceptionAsNecessary(
env, BAD_VALUE, ACTION_CODE_FATAL,
"Error converting Java string to native");
return; return;
} }
names->emplace_back(cstr); names->emplace_back(cstr);
@@ -3437,6 +3519,7 @@ static jboolean android_media_MediaCodec_LinearBlock_checkCompatible(
} }
status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible); status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible);
if (err != OK) { if (err != OK) {
// TODO: CodecErrorLog
throwExceptionAsNecessary(env, err); throwExceptionAsNecessary(env, err);
} }
return isCompatible; return isCompatible;

View File

@@ -176,6 +176,8 @@ struct JMediaCodec : public AHandler {
const sp<ICrypto> &getCrypto() { return mCrypto; } const sp<ICrypto> &getCrypto() { return mCrypto; }
std::string getExceptionMessage(const char *msg) const;
protected: protected:
virtual ~JMediaCodec(); virtual ~JMediaCodec();