Index: base/android/jni_android.cc |
diff --git a/base/android/jni_android.cc b/base/android/jni_android.cc |
index 1b7c72c82fa7baa830bb7a8a95896140fb7f0774..2a01063d1ed5c6285e3cef73108f0476b5347384 100644 |
--- a/base/android/jni_android.cc |
+++ b/base/android/jni_android.cc |
@@ -6,12 +6,17 @@ |
#include <map> |
+#include "base/android/build_info.h" |
+#include "base/android/jni_string.h" |
#include "base/atomicops.h" |
#include "base/lazy_instance.h" |
#include "base/logging.h" |
#include "base/threading/platform_thread.h" |
namespace { |
+using base::android::GetClass; |
+using base::android::GetMethodID; |
+using base::android::ScopedJavaLocalRef; |
JavaVM* g_jvm = NULL; |
@@ -49,7 +54,48 @@ const base::subtle::AtomicWord kUnlocked = 0; |
const base::subtle::AtomicWord kLocked = 1; |
base::subtle::AtomicWord g_method_id_map_lock = kUnlocked; |
+std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) { |
+ ScopedJavaLocalRef<jclass> throwable_clazz = |
+ GetClass(env, "java/lang/Throwable"); |
+ jmethodID throwable_printstacktrace = |
+ GetMethodID(env, throwable_clazz, "printStackTrace", |
+ "(Ljava/io/PrintStream;)V"); |
+ |
+ // Create an instance of ByteArrayOutputStream. |
+ ScopedJavaLocalRef<jclass> bytearray_output_stream_clazz = |
+ GetClass(env, "java/io/ByteArrayOutputStream"); |
+ jmethodID bytearray_output_stream_constructor = |
+ GetMethodID(env, bytearray_output_stream_clazz, "<init>", "()V"); |
+ jmethodID bytearray_output_stream_tostring = |
+ GetMethodID(env, bytearray_output_stream_clazz, "toString", |
+ "()Ljava/lang/String;"); |
+ ScopedJavaLocalRef<jobject> bytearray_output_stream(env, |
+ env->NewObject(bytearray_output_stream_clazz.obj(), |
+ bytearray_output_stream_constructor)); |
+ |
+ // Create an instance of PrintStream. |
+ ScopedJavaLocalRef<jclass> printstream_clazz = |
+ GetClass(env, "java/io/PrintStream"); |
+ jmethodID printstream_constructor = |
+ GetMethodID(env, printstream_clazz, "<init>", |
+ "(Ljava/io/OutputStream;)V"); |
+ ScopedJavaLocalRef<jobject> printstream(env, |
+ env->NewObject(printstream_clazz.obj(), printstream_constructor, |
+ bytearray_output_stream.obj())); |
+ |
+ // Call Throwable.printStackTrace(PrintStream) |
+ env->CallVoidMethod(java_throwable, throwable_printstacktrace, |
+ printstream.obj()); |
+ |
+ // Call ByteArrayOutputStream.toString() |
+ ScopedJavaLocalRef<jstring> exception_string( |
+ env, static_cast<jstring>( |
+ env->CallObjectMethod(bytearray_output_stream.obj(), |
+ bytearray_output_stream_tostring))); |
+ |
+ return ConvertJavaStringToUTF8(exception_string); |
} |
+} // namespace |
namespace base { |
namespace android { |
@@ -250,15 +296,31 @@ bool HasException(JNIEnv* env) { |
bool ClearException(JNIEnv* env) { |
if (!HasException(env)) |
return false; |
+ env->ExceptionDescribe(); |
env->ExceptionClear(); |
return true; |
} |
void CheckException(JNIEnv* env) { |
- if (HasException(env)) { |
- env->ExceptionDescribe(); |
+ if (!HasException(env)) return; |
+ |
+ // Ugh, we are going to die, might as well tell breakpad about it. |
+ jthrowable java_throwable = env->ExceptionOccurred(); |
+ if (!java_throwable) { |
+ // Nothing we can do. |
CHECK(false); |
} |
+ |
+ // Clear the pending exception, we do have a reference to it. |
+ env->ExceptionClear(); |
+ |
+ // Set the exception_string in BuildInfo so that breakpad can read it. |
+ // RVO should avoid any extra copies of the exception string. |
+ base::android::BuildInfo::GetInstance()->set_java_exception_info( |
+ GetJavaExceptionInfo(env, java_throwable)); |
+ |
+ // Now, feel good about it and die. |
+ CHECK(false); |
} |
} // namespace android |