in cpp/profiler/SignalHandler.cpp [187:299]
void SignalHandler::AndroidAwareSigaction(
int signum,
SigactionPtr handler,
struct sigaction* oldact) {
#ifdef __ANDROID__
//
// On Android, we need to look up sigaction64 or sigaction directly from libc
// or otherwise we'll get the wrappers from sigchain.
//
// These wrappers do not work for our purposes because they run art's signal
// handling before our handler and that signal handling can be misled to
// believe it's in art code when in fact it's in SamplingProfiler unwinding.
//
// Further, we must use sigaction64 if available as otherwise we may hit a bug
// in bionic where sigaction`libc calls sigaction64`sigchain.
// See commit 11623dd60dd0f531fbc1cbf108680ba850acaf2f in AOSP.
//
static struct {
int (*libc_sigaction64)(
int,
const struct sigaction64*,
struct sigaction64*) = nullptr;
int (*libc_sigemptyset64)(sigset64_t*) = nullptr;
int (*libc_sigismember64)(sigset64_t*, int) = nullptr;
int (*libc_sigaction)(int, const struct sigaction*, struct sigaction*) =
nullptr;
bool lookups_complete = false;
} signal_state;
if (!signal_state.lookups_complete) {
auto libc = dlopen("libc.so", RTLD_LOCAL);
if (!libc) {
std::string error("Missing libc.so: ");
throw std::runtime_error(error + dlerror());
}
signal_state.libc_sigaction64 =
reinterpret_cast<decltype(signal_state.libc_sigaction64)>(
dlsym(libc, "sigaction64"));
if (signal_state.libc_sigaction64) {
signal_state.libc_sigemptyset64 =
reinterpret_cast<decltype(signal_state.libc_sigemptyset64)>(
dlsym(libc, "sigemptyset64"));
signal_state.libc_sigismember64 =
reinterpret_cast<decltype(signal_state.libc_sigismember64)>(
dlsym(libc, "sigismember64"));
} else {
signal_state.libc_sigaction =
reinterpret_cast<decltype(signal_state.libc_sigaction)>(
dlsym(libc, "sigaction"));
}
signal_state.lookups_complete = true;
dlclose(libc);
}
int result = 0;
if (signal_state.libc_sigaction64) {
//
// sigaction64 is available.
// Convert from struct sigaction to struct sigaction64 and back
// and call it directly.
//
// Note that the conversion from sigset64_t to sigset_t is lossy,
// we lose real-time signals!
//
struct sigaction64 action64 {
.sa_sigaction = handler, .sa_flags = kSignalHandlerFlags,
};
signal_state.libc_sigemptyset64(&action64.sa_mask);
struct sigaction64 oldaction64;
result = signal_state.libc_sigaction64(signum, &action64, &oldaction64);
struct sigaction oldaction {
.sa_flags = oldaction64.sa_flags,
};
if (oldaction.sa_flags & SA_SIGINFO) {
oldaction.sa_sigaction = oldaction64.sa_sigaction;
} else {
oldaction.sa_handler = oldaction64.sa_handler;
}
sigemptyset(&oldaction.sa_mask);
for (int i = 0; i < NSIG; i++) {
if (signal_state.libc_sigismember64(&oldaction64.sa_mask, i)) {
sigaddset(&oldaction.sa_mask, i);
}
}
*oldact = oldaction;
} else {
struct sigaction action {
.sa_sigaction = handler, .sa_flags = kSignalHandlerFlags,
};
sigemptyset(&action.sa_mask);
result = signal_state.libc_sigaction(signum, &action, oldact);
}
if (result != 0) {
throw std::system_error(errno, std::system_category());
}
#else // not __ANDROID__
struct sigaction action {};
action.sa_flags = kSignalHandlerFlags;
action.sa_sigaction = handler;
sigemptyset(&action.sa_mask);
if (sigaction(signum, &action, oldact)) {
throw std::system_error(errno, std::system_category());
}
#endif
}