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