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.
4
5 #include "base/android/java_exception_reporter.h"
6
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/debug/dump_without_crashing.h"
11 #include "base/functional/bind.h"
12 #include "base/functional/callback.h"
13 #include "base/lazy_instance.h"
14 #include "base/logging.h"
15 #include "build/robolectric_buildflags.h"
16
17 #if BUILDFLAG(IS_ROBOLECTRIC)
18 #include "base/base_robolectric_jni/JavaExceptionReporter_jni.h" // nogncheck
19 #else
20 #include "base/base_jni/JavaExceptionReporter_jni.h"
21 #endif
22
23 using base::android::JavaParamRef;
24 using base::android::JavaRef;
25
26 namespace base {
27 namespace android {
28
29 namespace {
30
31 JavaExceptionCallback g_java_exception_callback;
32
33 using JavaExceptionFilter =
34 base::RepeatingCallback<bool(const JavaRef<jthrowable>&)>;
35
36 LazyInstance<JavaExceptionFilter>::Leaky g_java_exception_filter =
37 LAZY_INSTANCE_INITIALIZER;
38
39 } // namespace
40
InitJavaExceptionReporter()41 void InitJavaExceptionReporter() {
42 JNIEnv* env = base::android::AttachCurrentThread();
43 // Since JavaExceptionReporter#installHandler will chain through to the
44 // default handler, the default handler should cause a crash as if it's a
45 // normal java exception. Prefer to crash the browser process in java rather
46 // than native since for webview, the embedding app may have installed its
47 // own JavaExceptionReporter handler and would expect it to be called.
48 constexpr bool crash_after_report = false;
49 SetJavaExceptionFilter(
50 base::BindRepeating([](const JavaRef<jthrowable>&) { return true; }));
51 Java_JavaExceptionReporter_installHandler(env, crash_after_report);
52 }
53
InitJavaExceptionReporterForChildProcess()54 void InitJavaExceptionReporterForChildProcess() {
55 JNIEnv* env = base::android::AttachCurrentThread();
56 constexpr bool crash_after_report = true;
57 SetJavaExceptionFilter(
58 base::BindRepeating([](const JavaRef<jthrowable>&) { return true; }));
59 Java_JavaExceptionReporter_installHandler(env, crash_after_report);
60 }
61
SetJavaExceptionFilter(JavaExceptionFilter java_exception_filter)62 void SetJavaExceptionFilter(JavaExceptionFilter java_exception_filter) {
63 g_java_exception_filter.Get() = std::move(java_exception_filter);
64 }
65
SetJavaExceptionCallback(JavaExceptionCallback callback)66 void SetJavaExceptionCallback(JavaExceptionCallback callback) {
67 DCHECK(!g_java_exception_callback || !callback);
68 g_java_exception_callback = callback;
69 }
70
GetJavaExceptionCallback()71 JavaExceptionCallback GetJavaExceptionCallback() {
72 return g_java_exception_callback;
73 }
74
SetJavaException(const char * exception)75 void SetJavaException(const char* exception) {
76 // No need to print exception because they are already logged via
77 // env->ExceptionDescribe() within jni_android.cc.
78 if (g_java_exception_callback) {
79 g_java_exception_callback(exception);
80 }
81 }
82
JNI_JavaExceptionReporter_ReportJavaException(JNIEnv * env,jboolean crash_after_report,const JavaParamRef<jthrowable> & e)83 void JNI_JavaExceptionReporter_ReportJavaException(
84 JNIEnv* env,
85 jboolean crash_after_report,
86 const JavaParamRef<jthrowable>& e) {
87 std::string exception_info = base::android::GetJavaExceptionInfo(env, e);
88 bool should_report_exception = g_java_exception_filter.Get().Run(e);
89 if (should_report_exception) {
90 SetJavaException(exception_info.c_str());
91 }
92 if (crash_after_report) {
93 LOG(ERROR) << exception_info;
94 LOG(FATAL) << "Uncaught exception";
95 }
96 if (should_report_exception) {
97 base::debug::DumpWithoutCrashing();
98 SetJavaException(nullptr);
99 }
100 }
101
JNI_JavaExceptionReporter_ReportJavaStackTrace(JNIEnv * env,std::string & stack_trace)102 void JNI_JavaExceptionReporter_ReportJavaStackTrace(JNIEnv* env,
103 std::string& stack_trace) {
104 SetJavaException(stack_trace.c_str());
105 base::debug::DumpWithoutCrashing();
106 SetJavaException(nullptr);
107 }
108
109 } // namespace android
110 } // namespace base
111