1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/android/java_exception_reporter.h"
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.h"
9 #include "base/android/scoped_java_ref.h"
10 #include "base/base_jni/JavaExceptionReporter_jni.h"
11 #include "base/debug/dump_without_crashing.h"
12 #include "base/functional/bind.h"
13 #include "base/functional/callback.h"
14 #include "base/lazy_instance.h"
16 using base::android::JavaParamRef;
17 using base::android::JavaRef;
24 void (*g_java_exception_callback)(const char*);
26 using JavaExceptionFilter =
27 base::RepeatingCallback<bool(const JavaRef<jthrowable>&)>;
29 LazyInstance<JavaExceptionFilter>::Leaky g_java_exception_filter =
30 LAZY_INSTANCE_INITIALIZER;
34 void InitJavaExceptionReporter() {
35 JNIEnv* env = base::android::AttachCurrentThread();
36 // Since JavaExceptionReporter#installHandler will chain through to the
37 // default handler, the default handler should cause a crash as if it's a
38 // normal java exception. Prefer to crash the browser process in java rather
39 // than native since for webview, the embedding app may have installed its
40 // own JavaExceptionReporter handler and would expect it to be called.
41 constexpr bool crash_after_report = false;
42 SetJavaExceptionFilter(
43 base::BindRepeating([](const JavaRef<jthrowable>&) { return true; }));
44 Java_JavaExceptionReporter_installHandler(env, crash_after_report);
47 void InitJavaExceptionReporterForChildProcess() {
48 JNIEnv* env = base::android::AttachCurrentThread();
49 constexpr bool crash_after_report = true;
50 SetJavaExceptionFilter(
51 base::BindRepeating([](const JavaRef<jthrowable>&) { return true; }));
52 Java_JavaExceptionReporter_installHandler(env, crash_after_report);
55 void SetJavaExceptionFilter(JavaExceptionFilter java_exception_filter) {
56 g_java_exception_filter.Get() = std::move(java_exception_filter);
59 void SetJavaExceptionCallback(void (*callback)(const char*)) {
60 DCHECK(!g_java_exception_callback);
61 g_java_exception_callback = callback;
64 void SetJavaException(const char* exception) {
65 // No need to print exception because they are already logged via
66 // env->ExceptionDescribe() within jni_android.cc.
67 if (g_java_exception_callback) {
68 g_java_exception_callback(exception);
72 void JNI_JavaExceptionReporter_ReportJavaException(
74 jboolean crash_after_report,
75 const JavaParamRef<jthrowable>& e) {
76 std::string exception_info = base::android::GetJavaExceptionInfo(env, e);
77 bool should_report_exception = g_java_exception_filter.Get().Run(e);
78 if (should_report_exception) {
79 SetJavaException(exception_info.c_str());
81 if (crash_after_report) {
82 LOG(ERROR) << exception_info;
83 LOG(FATAL) << "Uncaught exception";
85 if (should_report_exception) {
86 base::debug::DumpWithoutCrashing();
87 SetJavaException(nullptr);
91 void JNI_JavaExceptionReporter_ReportJavaStackTrace(
93 const JavaParamRef<jstring>& stack_trace) {
94 SetJavaException(ConvertJavaStringToUTF8(stack_trace).c_str());
95 base::debug::DumpWithoutCrashing();
96 SetJavaException(nullptr);
99 } // namespace android