xref: /aosp_15_r20/external/cronet/base/android/java_exception_reporter.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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