美文网首页
通过自定义SIGQUIT处理函数,收集Anr堆栈信息

通过自定义SIGQUIT处理函数,收集Anr堆栈信息

作者: vb12 | 来源:发表于2023-03-16 14:44 被阅读0次

在android手机上, 当anr发生时系统会在/data/anr/trace.txt文件中留下堆栈信息(实际上是系统触发应用进程自己写入的).但这个文件对于没有root的手机是无法获取的, 这对于我们需要收集线上anr信息的需求来说, 是比较头疼的.

下面是一个比较常见的办法, 在native层通过自定义SIGQUIT信号处理函数, 来找到anr发生的切入时机, 手工收集线程堆栈, 并进行处理(存入本地文件,或者回传服务器).

原理

当应用进程发生anr时, System server进程(具体来说是ams)会向进程发送SIGQUIT信号, 让进程主动dump出线程堆栈信息到/data/anr/trace.txt. 这个文件对应用来说可写, 但不可读.
具体负责这个dump操作的线程是Signal Catcher线程.
我们在native层可以通过修改替换SIGQUIT的处理函数, 来得到控制权, 从而进行anr数据收集.

关键点

  1. 替换修改SIGQUIT处理函数
struct sigaction sa{};
    sa.sa_sigaction = signalHandler;
    sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTART;
    // 设置一个新的sigaction
    if (sigaction(SIGQUIT, &sa, nullptr) == -1) {
        return false;
    }

signalHandler就是我们自定义的函数. 也就是我们拿到控制权后的代码执行入口

  1. 创建子线程
    为什么创建子线程, 是因为此时应用主线程被阻塞了, 无法回调java层jvm代码
std::thread javaCallbackThread(&JniSignalHandler::callJavaMethod, this, sig);
javaCallbackThread.detach();

一定记住新创建的子线程,必须先关联到jvm环境, 否则回调java代码会报错

   JNIEnv* env;
    jint attachResult = mJVM->AttachCurrentThread(&env, nullptr);
....
  1. 回调java层, 收集线程堆栈.
    当然也可以尝试在native层直接收集堆栈信息, 只是麻烦一点.

知识点

  1. 为什么主线程anr不响应了, 仍然可以执行信号处理函数
    当一个Android应用发生ANR时,主线程可能因为某些原因(如死锁、耗时操作等)处于阻塞状态。在这种情况下,主线程收到一个信号(如SIGQUIT),它通常仍然可以调用信号处理函数。

  2. 如果是在native层C++创建的线程, 是不能直接用来回调java代码的, 需要先AttachCurrentThread.

遗留问题

  1. 为什么Signal Catcher 可以得到所有线程的id(是linux线程的id,不是java thread的tid), 而我得不到, 还在想办法. 好像需要研究下art中对thread的实现
  2. 可能存在手机很卡, cpu占用高, 导致本应用没有来记得响应, 被认为anr了, 属于误伤的情况, 如何分别这总情况, 有说可以检查getProcessesInErrorState()返回的proc的condition是否被打标签认为是not respond了, 但试了下至少小米手机不行.

演示代码

https://github.com/shaopx/MyAPMTest

相关文章

  • Android Anr线上监控

    Anr信息收集: ProcessErrorStateInfo tomstone信息 主线程的堆栈采样信息 主线程 ...

  • linklist超大导致的ANR

    通过ANR的堆栈分析,ANR的堆栈都是停在了linklist的contains()函数。通过源码分析,系统提供的l...

  • Error 泛型

    Error 异常处理 错误处理 错误类型 自定义错误 可以通过Error协议自定义运行时的错误信息 函数内部通过...

  • ANR系列

    ANR(0)---理解Android ANR的触发原理ANR(1)---理解Android ANR的信息收集过程A...

  • Android ANR分析详解

    traces文件分析 在看这篇文章之前需要对anr有了解各个应用进程和系统进程的函数堆栈信息都输出到了/data/...

  • 函数调用堆栈

    函数调用堆栈 函数调用堆栈最常用的是收集crash信息,解决问题用的,这方面网上有很多的资料,也有成熟的第三方,如...

  • Android CRASH ANR 日志收集

    Android CRASH ANR 日志收集 需求:如图 收集实现方式 通过现成的bugly收集 在bugly上报...

  • HIVE UDTF 自定义函数

    HIVE UDTF 自定义函数 关键词:HIVE UDTF 开发 实例Hive运行用户自定义函数对数据信息处理,...

  • 为什么调用 lua_pcall

    原理:C和lua通过一个堆栈进行交互,lua_pcall的用途就是执行堆栈里的函数,先将lua里的函数压入堆栈,然...

  • Swift5 _09_Error处理_泛型

    自定义错误 Swift中可以通过Error协议自定义运行时的错误信息 函数内部通过throw抛出自定义Error,...

网友评论

      本文标题:通过自定义SIGQUIT处理函数,收集Anr堆栈信息

      本文链接:https://www.haomeiwen.com/subject/ndqdrdtx.html