summaryrefslogtreecommitdiffstats
path: root/android_webview/common/aw_crash_handler.cc
blob: fbd4285b05056288a19f2f5894340486687507e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// 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