123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- // Copyright 2015 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "base/android/java_exception_reporter.h"
- #include "base/android/jni_android.h"
- #include "base/android/jni_string.h"
- #include "base/android/scoped_java_ref.h"
- #include "base/base_jni_headers/JavaExceptionReporter_jni.h"
- #include "base/bind.h"
- #include "base/callback.h"
- #include "base/debug/dump_without_crashing.h"
- #include "base/lazy_instance.h"
- using base::android::JavaParamRef;
- using base::android::JavaRef;
- namespace base {
- namespace android {
- namespace {
- void (*g_java_exception_callback)(const char*);
- using JavaExceptionFilter =
- base::RepeatingCallback<bool(const JavaRef<jthrowable>&)>;
- LazyInstance<JavaExceptionFilter>::Leaky g_java_exception_filter =
- LAZY_INSTANCE_INITIALIZER;
- } // namespace
- void InitJavaExceptionReporter() {
- JNIEnv* env = base::android::AttachCurrentThread();
- // Since JavaExceptionReporter#installHandler will chain through to the
- // default handler, the default handler should cause a crash as if it's a
- // normal java exception. Prefer to crash the browser process in java rather
- // than native since for webview, the embedding app may have installed its
- // own JavaExceptionReporter handler and would expect it to be called.
- constexpr bool crash_after_report = false;
- SetJavaExceptionFilter(
- base::BindRepeating([](const JavaRef<jthrowable>&) { return true; }));
- Java_JavaExceptionReporter_installHandler(env, crash_after_report);
- }
- void InitJavaExceptionReporterForChildProcess() {
- JNIEnv* env = base::android::AttachCurrentThread();
- constexpr bool crash_after_report = true;
- SetJavaExceptionFilter(
- base::BindRepeating([](const JavaRef<jthrowable>&) { return true; }));
- Java_JavaExceptionReporter_installHandler(env, crash_after_report);
- }
- void SetJavaExceptionFilter(JavaExceptionFilter java_exception_filter) {
- g_java_exception_filter.Get() = std::move(java_exception_filter);
- }
- void SetJavaExceptionCallback(void (*callback)(const char*)) {
- DCHECK(!g_java_exception_callback);
- g_java_exception_callback = callback;
- }
- void SetJavaException(const char* exception) {
- // No need to print exception because they are already logged via
- // env->ExceptionDescribe() within jni_android.cc.
- if (g_java_exception_callback) {
- g_java_exception_callback(exception);
- }
- }
- void JNI_JavaExceptionReporter_ReportJavaException(
- JNIEnv* env,
- jboolean crash_after_report,
- const JavaParamRef<jthrowable>& e) {
- std::string exception_info = base::android::GetJavaExceptionInfo(env, e);
- bool should_report_exception = g_java_exception_filter.Get().Run(e);
- if (should_report_exception) {
- SetJavaException(exception_info.c_str());
- }
- if (crash_after_report) {
- LOG(ERROR) << exception_info;
- LOG(FATAL) << "Uncaught exception";
- }
- if (should_report_exception) {
- base::debug::DumpWithoutCrashing();
- SetJavaException(nullptr);
- }
- }
- void JNI_JavaExceptionReporter_ReportJavaStackTrace(
- JNIEnv* env,
- const JavaParamRef<jstring>& stack_trace) {
- SetJavaException(ConvertJavaStringToUTF8(stack_trace).c_str());
- base::debug::DumpWithoutCrashing();
- SetJavaException(nullptr);
- }
- } // namespace android
- } // namespace base
|