How Android Handles ANR SIGQUIT: Signal Interception Explained
This article explains how Android captures ANR events by intercepting the SIGQUIT signal, covering the relevant signal‑handling functions (kill, signal, sigaction, sigwait, pthread_sigmask), their differences, the SignalCatcher thread implementation, and how developers can create custom SIGQUIT monitors for ANR analysis.
Background
ANR (Application Not Responding) frequency is an important metric for Android user experience. Since Android 6.0+, the /data/anr/traces.txt file is no longer accessible due to permission restrictions, so we need alternative ways to capture ANR, namely intercepting the SIGQUIT(3) signal.
Signal Handling Functions
To intercept SIGQUIT, we need to understand related system calls: kill, signal, sigaction, sigwait, pthread_sigmask.
kill
Header : #include <signal.h>
Function definition : int kill(pid_t pid, int signo)
Description : Sends a signal to a process; Android AMS uses Process.sendSignal(pid, signal), which ultimately calls kill.
signal
Header : #include <signal.h>
Function definition : sig_t signal(int signum, sig_t handler)
Description : Sets the handler for a given signal. If handler is SIG_DFL, the default action is used; SIG_IGN ignores the signal; otherwise the specified handler is called. Valid signals include SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM, etc.
sigaction
Header : #include <signal.h>
Function definition : int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
Description : Configures the handling of a signal. The struct sigaction is defined as:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};sa_handler is equivalent to the handler argument of signal(). sa_sigaction is used when SA_SIGINFO flag is set, allowing additional information. sa_mask specifies signals to block during handling. sa_flags can include SA_RESETHAND, SA_RESTART, SA_NODEFER, etc.
sigwait
Header : #include <signal.h>
Function definition : int sigwait(const sigset_t *set, int *sig)
Description : Waits synchronously for a signal from the specified set, returning the signal number. It is useful for dedicated signal‑handling threads. Recommendations: do not block SIGSTOP or SIGKILL; do not block SIGFPE, SIGILL, SIGSEGV, SIGBUS; ensure the signal set is blocked in all threads before calling sigwait; use kill() to send signals to the whole process, not pthread_kill().
pthread_sigmask
Header : #include <signal.h>
Function definition : int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
Description : Sets the calling thread’s signal mask, allowing selective blocking or unblocking of signals.
Differences Between signal, sigaction, and sigwait
signal is a legacy wrapper whose functionality is subsumed by sigaction; both ultimately invoke the rt_sigaction system call. sigaction provides more control and is the preferred API. sigwait differs by delivering signals synchronously to a waiting thread; if a signal is also caught by sigaction, the kernel decides whether to wake the waiting thread or invoke the handler, but not both.
Android ANR SIGQUIT Handling
When an ANR occurs, Android’s ActivityManagerService forks a process via Zygote, which creates a dedicated “SignalCatcher” thread. AMS sends SIGQUIT(3) to the target process; the SignalCatcher thread waits for SIGQUIT (and SIGUSR1) using sigwait and dumps thread stacks to /data/anr/traces.txt.
SignalCatcher Thread Creation
The SignalCatcher thread is created during Runtime initialization. Runtime::BlockSignals adds SIGPIPE, SIGQUIT, and SIGUSR1 to a SignalSet and blocks them using pthread_sigmask, ensuring they are handled only by the SignalCatcher.
SignalCatcher Run Loop
void* SignalCatcher::Run(void* arg) {
SignalSet signals;
signals.Add(SIGQUIT);
signals.Add(SIGUSR1);
while (true) {
int signal_number = signal_catcher->WaitForSignal(self, signals);
if (signal_catcher->ShouldHalt()) {
runtime->DetachCurrentThread();
return nullptr;
}
switch (signal_number) {
case SIGQUIT:
signal_catcher->HandleSigQuit();
break;
case SIGUSR1:
signal_catcher->HandleSigUsr1();
break;
default:
LOG(ERROR) << "Unexpected signal " << signal_number;
break;
}
}
}This design guarantees that SIGQUIT and SIGUSR1 are processed only by the SignalCatcher, preventing other threads from interfering and preserving stack integrity.
Custom SIGQUIT Interception
Developers can implement their own SIGQUIT monitor by unblocking SIGQUIT in the main thread with pthread_sigmask(SIG_UNBLOCK, …) and installing a sigaction handler with SA_ONSTACK | SA_SIGINFO. Example code:
void RunSigQuitMonitor() {
sigset_t set, old_set;
sigemptyset(&set);
sigaddset(&set, SIGQUIT);
int r = pthread_sigmask(SIG_UNBLOCK, &set, &old_set);
if (r != 0) return;
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGQUIT);
sa.sa_sigaction = SignalHandler;
sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
if (sigaction(SIGQUIT, &sa, &old_handler) != 0) {
pthread_sigmask(SIG_SETMASK, &old_set, NULL);
}
}By doing so, the custom handler can capture ANR information without interfering with the system’s SignalCatcher.
Conclusion
Understanding Android’s SIGQUIT handling enables developers to quickly implement custom ANR monitoring solutions.
References
https://baike.baidu.com/item/kill/2680256
https://baike.baidu.com/item/signal.h/7316160?fr=aladdin
https://baike.baidu.com/item/sigaction
https://baike.baidu.com/item/sigwait
https://baike.baidu.com/item/pthread_sigmask
Source analysis of signal vs sigaction: https://blog.csdn.net/wangzuxi/article/details/44814825
Libev source analysis 06: https://www.cnblogs.com/gqtcgq/p/7247097.html
Android application process creation: https://www.jianshu.com/p/b4cb8608d7f
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
