监听 Android ANR 信号并获取所有方法栈信息

💡 原文中文,约15400字,阅读约需37分钟。
📝

内容提要

本文介绍了如何监听Android ANR信号并获取方法栈信息。首先,通过监听SIGQUIT信号来替换原始信号处理函数,并获取原始信号处理函数的地址。然后,判断收到的信号是否为ANR信号,并向Signal Catcher线程发送信号。接下来,介绍了如何获取Signal Catcher线程的tid,并通过hook write()方法来获取ANR dump文件。最后,通过发送SIGQUIT信号给Signal Catcher线程,主动获取所有线程的方法栈信息。

🔎

延伸解读

为何需要绕过系统限制获取ANR信息

Android未提供ANR回调接口,线上用户无法直接获取dump文件。系统默认将ANR信息写入/data/anr目录,但该目录需要root权限才能读取,普通用户难以访问。因此,通过监听SIGQUIT信号并hook write方法,可以在应用进程内捕获ANR时的线程栈信息,为线上问题分析提供可能。

信号处理中的关键判断与转发

收到SIGQUIT信号后,需判断发送信号的进程不是当前进程,因为应用自身也可能发送该信号。确认是ANR信号后,再通过syscall向Signal Catcher线程发送SIGQUIT,触发其dump线程栈。这一转发机制确保了ANR处理流程的正确性,避免误判。

Hook write方法的版本适配要点

不同Android版本中,Signal Catcher的write方法位于不同的so库。例如API 30及以上或24、25需hook libc.so,API 29需hook libbase.so,其他版本则hook libart.so。使用xHook注册并刷新hook,可拦截write调用,将dump内容重定向到自定义文件,实现ANR信息的持久化。

主动获取线程栈的实用技巧

除了被动等待ANR信号,还可以主动向Signal Catcher线程发送SIGQUIT信号,获取当前所有线程的栈信息。这种方式适用于需要实时分析线程状态的场景,如卡顿排查。通过hook write方法,同样能捕获到完整的dump文件,包含Java和Native线程栈、状态及锁信息,便于深入分析。

❓

Q&A

如何监听Android的ANR信号?

可以通过解除SIGQUIT信号的默认处理,注册自定义的信号处理函数anrSignalHandler来监听ANR信号。

ANR信号的默认处理是什么?

ANR信号的默认处理是SIGQUIT,Android系统默认不允许替换该信号的处理函数。

如何获取Signal Catcher线程的tid?

可以通过读取/proc/[pid]/task目录下的线程信息来获取Signal Catcher线程的tid。

如何主动获取所有线程的栈信息?

可以通过向Signal Catcher线程发送SIGQUIT信号来主动获取所有线程的栈信息。

ANR dump文件包含哪些信息?

ANR dump文件包含Java线程和Native线程的栈信息、状态、锁信息等,有助于问题分析。

如何通过hook获取ANR dump文件?

可以通过hook Signal Catcher线程的write()方法,来获取ANR dump文件的内容。

🏷️

标签

➡️

继续阅读