blob: fbd4285b05056288a19f2f5894340486687507e9 [file] [log] [blame]
// Copyright 2014 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 "android_webview/common/aw_crash_handler.h"
#include <android/log.h>
#include <signal.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <unistd.h>
#include "base/logging.h"
namespace {
const int kExceptionSignals[] = {
SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS
};
struct sigaction old_handlers[arraysize(kExceptionSignals)];
bool crash_handler_registered;
std::string g_crash_msg;
const char* g_crash_msg_ptr; // Avoid invoking STL magic in a signal handler.
void AwExceptionHandler(int sig, siginfo_t* info, void* uc) {
if (g_crash_msg_ptr != NULL)
__android_log_write(ANDROID_LOG_ERROR, "chromium", g_crash_msg_ptr);
// Detect if some buggy code in the embedder did reinstall the handler using
// signal() instead of sigaction() (which would cause |info| to be invalid).
struct sigaction cur_handler;
if (sigaction(sig, NULL, &cur_handler) != 0 ||
(cur_handler.sa_flags & SA_SIGINFO) == 0) {
info = NULL;
}
// We served our purpose. Now restore the old crash handlers. If the embedder
// did register a custom crash handler, it will be invoked by the kernel after
// this function returns. Otherwise, this will end up invoking the default
// signal disposition.
for (uint32_t i = 0; i < arraysize(kExceptionSignals); ++i) {
if (sigaction(kExceptionSignals[i], &old_handlers[i], NULL) == -1) {
signal(kExceptionSignals[i], SIG_DFL);
}
}
if ((info != NULL && info->si_pid) || sig == SIGABRT) {
// This signal was triggered by somebody sending us the signal with kill().
// In order to retrigger it, we have to queue a new signal by calling
// kill() ourselves. The special case (si_pid == 0 && sig == SIGABRT) is
// due to the kernel sending a SIGABRT from a user request via SysRQ.
if (syscall(__NR_tgkill, getpid(), syscall(__NR_gettid), sig) < 0) {
// If we failed to kill ourselves resort to terminating uncleanly.
exit(1);
}
}
}
} // namespace
namespace android_webview {
namespace crash_handler {
void RegisterCrashHandler(const std::string& version) {
if (crash_handler_registered) {
NOTREACHED();
return;
}
g_crash_msg = "### WebView crash. " + version;
g_crash_msg_ptr = g_crash_msg.c_str();
// Fail if unable to store all the old handlers.
for (uint32_t i = 0; i < arraysize(kExceptionSignals); ++i) {
if (sigaction(kExceptionSignals[i], NULL, &old_handlers[i]) == -1) {
LOG(ERROR) << "Error while trying to retrieve old handler for signal "
<< kExceptionSignals[i] << ")";
return;
}
}
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
// Mask all exception signals when we're handling one of them.
for (uint32_t i = 0; i < arraysize(kExceptionSignals); ++i)
sigaddset(&sa.sa_mask, kExceptionSignals[i]);
sa.sa_sigaction = AwExceptionHandler;
sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
for (uint32_t i = 0; i < arraysize(kExceptionSignals); ++i) {
if (sigaction(kExceptionSignals[i], &sa, NULL) == -1) {
// At this point it is impractical to back out changes, and so failure to
// install a signal is intentionally ignored.
LOG(ERROR) << "Error while overriding handler for signal "
<< kExceptionSignals[i];
}
}
crash_handler_registered = true;
}
} // namespace crash_handler
} // namespace android_webview