Add java exception information to BuildInfo.

This information will be read by breakpad during minidump preparation to
upload any java stack trace.

BUG=
TEST=


Review URL: https://chromiumcodereview.appspot.com/10412045

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@138435 0039d316-1c4b-4281-b951-d872f2087c98
parent 299d7f1d
......@@ -58,6 +58,11 @@ BuildInfo* BuildInfo::GetInstance() {
return Singleton<BuildInfo, LeakySingletonTraits<BuildInfo> >::get();
}
void BuildInfo::set_java_exception_info(const std::string& info) {
DCHECK(!java_exception_info_) << "info should be set only once.";
java_exception_info_ = strndup(info.c_str(), 1024);
}
bool RegisterBuildInfo(JNIEnv* env) {
return RegisterNativesImpl(env);
}
......
......@@ -17,6 +17,9 @@ namespace android {
// BuildInfo is a singleton class that stores android build and device
// information. It will be called from Android specific java code and gets used
// primarily in crash reporting.
// It is also used to store the last java exception seen during JNI.
// TODO(nileshagrawal): Find a better place to store this info.
class BuildInfo {
public:
......@@ -60,6 +63,12 @@ class BuildInfo {
return package_version_name_;
}
const char* java_exception_info() const {
return java_exception_info_;
}
void set_java_exception_info(const std::string& info);
private:
BuildInfo();
......@@ -76,6 +85,7 @@ class BuildInfo {
char* android_build_fp_;
char* package_version_code_;
char* package_version_name_;
char* java_exception_info_;
DISALLOW_COPY_AND_ASSIGN(BuildInfo);
};
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment