cjhopman | 060e007 | 2015-05-06 21:37:48 | [diff] [blame] | 1 | // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
boliu | 9b51b51 | 2017-02-03 15:35:05 | [diff] [blame] | 5 | #include "base/android/java_exception_reporter.h" |
cjhopman | 060e007 | 2015-05-06 21:37:48 | [diff] [blame] | 6 | |
cjhopman | 060e007 | 2015-05-06 21:37:48 | [diff] [blame] | 7 | #include "base/android/jni_android.h" |
wnwen | 2c307f9f | 2016-04-11 21:48:18 | [diff] [blame] | 8 | #include "base/android/jni_string.h" |
Tobias Sargeant | 5e78771d | 2019-09-21 13:49:23 | [diff] [blame] | 9 | #include "base/android/scoped_java_ref.h" |
Eric Stevenson | c0926cb | 2019-06-19 15:03:16 | [diff] [blame] | 10 | #include "base/base_jni_headers/JavaExceptionReporter_jni.h" |
Tobias Sargeant | 5e78771d | 2019-09-21 13:49:23 | [diff] [blame] | 11 | #include "base/bind.h" |
Eric Seckler | b23de230 | 2020-05-26 13:05:36 | [diff] [blame] | 12 | #include "base/callback.h" |
cjhopman | 060e007 | 2015-05-06 21:37:48 | [diff] [blame] | 13 | #include "base/debug/dump_without_crashing.h" |
Tobias Sargeant | 5e78771d | 2019-09-21 13:49:23 | [diff] [blame] | 14 | #include "base/lazy_instance.h" |
cjhopman | 060e007 | 2015-05-06 21:37:48 | [diff] [blame] | 15 | |
torne | 8656011 | 2016-08-04 15:59:04 | [diff] [blame] | 16 | using base::android::JavaParamRef; |
Tobias Sargeant | 5e78771d | 2019-09-21 13:49:23 | [diff] [blame] | 17 | using base::android::JavaRef; |
torne | 8656011 | 2016-08-04 15:59:04 | [diff] [blame] | 18 | |
boliu | 9b51b51 | 2017-02-03 15:35:05 | [diff] [blame] | 19 | namespace base { |
cjhopman | 060e007 | 2015-05-06 21:37:48 | [diff] [blame] | 20 | namespace android { |
| 21 | |
Joshua Peraza | 7814da2 | 2018-07-10 21:37:50 | [diff] [blame] | 22 | namespace { |
| 23 | |
| 24 | void (*g_java_exception_callback)(const char*); |
| 25 | |
Tobias Sargeant | 5e78771d | 2019-09-21 13:49:23 | [diff] [blame] | 26 | using JavaExceptionFilter = |
| 27 | base::RepeatingCallback<bool(const JavaRef<jthrowable>&)>; |
| 28 | |
| 29 | LazyInstance<JavaExceptionFilter>::Leaky g_java_exception_filter; |
| 30 | |
Joshua Peraza | 7814da2 | 2018-07-10 21:37:50 | [diff] [blame] | 31 | } // namespace |
| 32 | |
cjhopman | 060e007 | 2015-05-06 21:37:48 | [diff] [blame] | 33 | void InitJavaExceptionReporter() { |
| 34 | JNIEnv* env = base::android::AttachCurrentThread(); |
Peter Wen | 5cd0b59 | 2020-02-20 03:17:05 | [diff] [blame] | 35 | // Since JavaExceptionReporter#installHandler will chain through to the |
| 36 | // default handler, the default handler should cause a crash as if it's a |
| 37 | // normal java exception. Prefer to crash the browser process in java rather |
| 38 | // than native since for webview, the embedding app may have installed its |
| 39 | // own JavaExceptionReporter handler and would expect it to be called. |
boliu | 328eda13 | 2017-02-10 16:39:57 | [diff] [blame] | 40 | constexpr bool crash_after_report = false; |
Tobias Sargeant | 5e78771d | 2019-09-21 13:49:23 | [diff] [blame] | 41 | SetJavaExceptionFilter( |
| 42 | base::BindRepeating([](const JavaRef<jthrowable>&) { return true; })); |
boliu | 328eda13 | 2017-02-10 16:39:57 | [diff] [blame] | 43 | Java_JavaExceptionReporter_installHandler(env, crash_after_report); |
| 44 | } |
| 45 | |
| 46 | void InitJavaExceptionReporterForChildProcess() { |
| 47 | JNIEnv* env = base::android::AttachCurrentThread(); |
| 48 | constexpr bool crash_after_report = true; |
Tobias Sargeant | 5e78771d | 2019-09-21 13:49:23 | [diff] [blame] | 49 | SetJavaExceptionFilter( |
| 50 | base::BindRepeating([](const JavaRef<jthrowable>&) { return true; })); |
boliu | 328eda13 | 2017-02-10 16:39:57 | [diff] [blame] | 51 | Java_JavaExceptionReporter_installHandler(env, crash_after_report); |
cjhopman | 060e007 | 2015-05-06 21:37:48 | [diff] [blame] | 52 | } |
| 53 | |
Tobias Sargeant | 5e78771d | 2019-09-21 13:49:23 | [diff] [blame] | 54 | void SetJavaExceptionFilter(JavaExceptionFilter java_exception_filter) { |
| 55 | g_java_exception_filter.Get() = std::move(java_exception_filter); |
| 56 | } |
| 57 | |
Joshua Peraza | 7814da2 | 2018-07-10 21:37:50 | [diff] [blame] | 58 | void SetJavaExceptionCallback(void (*callback)(const char*)) { |
| 59 | DCHECK(!g_java_exception_callback); |
| 60 | g_java_exception_callback = callback; |
| 61 | } |
| 62 | |
| 63 | void SetJavaException(const char* exception) { |
Garfield Tan | d5d663f | 2020-09-15 01:30:56 | [diff] [blame] | 64 | // No need to print exception because they are already logged via |
| 65 | // env->ExceptionDescribe() within jni_android.cc. |
| 66 | if (g_java_exception_callback) { |
| 67 | g_java_exception_callback(exception); |
| 68 | } |
Joshua Peraza | 7814da2 | 2018-07-10 21:37:50 | [diff] [blame] | 69 | } |
| 70 | |
Daniel Bratell | 7aacf95 | 2017-11-21 17:51:25 | [diff] [blame] | 71 | void JNI_JavaExceptionReporter_ReportJavaException( |
| 72 | JNIEnv* env, |
Daniel Bratell | 7aacf95 | 2017-11-21 17:51:25 | [diff] [blame] | 73 | jboolean crash_after_report, |
| 74 | const JavaParamRef<jthrowable>& e) { |
boliu | 328eda13 | 2017-02-10 16:39:57 | [diff] [blame] | 75 | std::string exception_info = base::android::GetJavaExceptionInfo(env, e); |
Tobias Sargeant | 5e78771d | 2019-09-21 13:49:23 | [diff] [blame] | 76 | bool should_report_exception = g_java_exception_filter.Get().Run(e); |
| 77 | if (should_report_exception) { |
| 78 | SetJavaException(exception_info.c_str()); |
| 79 | } |
boliu | 328eda13 | 2017-02-10 16:39:57 | [diff] [blame] | 80 | if (crash_after_report) { |
| 81 | LOG(ERROR) << exception_info; |
| 82 | LOG(FATAL) << "Uncaught exception"; |
| 83 | } |
Tobias Sargeant | 5e78771d | 2019-09-21 13:49:23 | [diff] [blame] | 84 | if (should_report_exception) { |
| 85 | base::debug::DumpWithoutCrashing(); |
| 86 | SetJavaException(nullptr); |
| 87 | } |
cjhopman | 060e007 | 2015-05-06 21:37:48 | [diff] [blame] | 88 | } |
| 89 | |
Daniel Bratell | 7aacf95 | 2017-11-21 17:51:25 | [diff] [blame] | 90 | void JNI_JavaExceptionReporter_ReportJavaStackTrace( |
| 91 | JNIEnv* env, |
Tobias Sargeant | 5e78771d | 2019-09-21 13:49:23 | [diff] [blame] | 92 | const JavaParamRef<jstring>& stack_trace) { |
| 93 | SetJavaException(ConvertJavaStringToUTF8(stack_trace).c_str()); |
wnwen | 2c307f9f | 2016-04-11 21:48:18 | [diff] [blame] | 94 | base::debug::DumpWithoutCrashing(); |
Joshua Peraza | 7814da2 | 2018-07-10 21:37:50 | [diff] [blame] | 95 | SetJavaException(nullptr); |
wnwen | 2c307f9f | 2016-04-11 21:48:18 | [diff] [blame] | 96 | } |
| 97 | |
cjhopman | 060e007 | 2015-05-06 21:37:48 | [diff] [blame] | 98 | } // namespace android |
boliu | 9b51b51 | 2017-02-03 15:35:05 | [diff] [blame] | 99 | } // namespace base |