Android ANR 分析(trace 文件的产生流程中)
接着分析最后一步向收集到的进程发送信号(Android5.0 之前是 dump 用的 SuspendAll 线程,收集信息之后用 ResumeAll 恢复。在 5.0 之后采用的是 checkPoint 进行 dump 信息)
发生 ANR 时,systemServer 进程会执行 dumpStackTraces 函数,在该函数中发 SIGQUIT 信号给对应的进程(上面有分析到)
处于安全考虑,进程之间是相互隔离的,即使系统进程也无法获取其他进程的信息,所以要借助于 IPC 通信,将指令发送到目标进程,目标进程接收到消息后,协助完成自身进程 Dump 信息并发送给系统进程。Android P 流程:
1.一个进程接收到了 SIGQIUT 信号的时候,SingaCatcher 线程的 WaitForSignal 函数会返回接着会调用到 HandlerSigQuit()函数。
2.hindleSigQuit()函数为:
3.DumpForSigQuit()函数:
这是读取的信息,但是什么时候去读取呢(什么时候才能保证获取到的却是是需要的东西,例如 GC 信息,当前分配了多少对象,这些打印一般都需要在 suspend 当前进程里面的所有的线程),接下来先分析这个 suspend 过程:
这个挂起 SupendAll 实在 Thread_list.cc 中实现的,他的作用就是用来 suspend 当前进程里面所有其他的线程(一般发生在 GC,DumpForSigQuit 等过程中)。SuspendAll 过程实现最重要的就是 ModifySupendCount(self,+1,false)这段语句他会修改对应 Thread 对象的 suspend 引用计数:
因为传入的 delta 值是+1 所以会先执行 AtmoicSetFlag()利用原子操作设置了 KSuspendRequest 标志位,代表当前这个线程有挂起请求。什么时候会进行检测这个标志位呢?这里涉及到了 checkPoint 的知识点最后讲解(在线程运行中进行上下文切换(例如 java 线程转换为 Native 线程)时就会运行 CheckSuspend 函数,这个函数才是真正的把当前线程 suspend:
可以看到检测到了 KSuspendRequest 标记就会执行 FullSuspend 函数,KSuspendRequest 标志位是用来 dump 线程的堆栈的,分析完了 SuspendAll 之后,再继续分析 FullSuspendCheck 函数:
调用 TransitionFromRunnableToSuspend()这个函数后,线程就进入了 KSuspended 状态,然后在调用 TransitionFromSuspendedToRunnablecpm 函数从 Suspend 状态切换到 Runnable 状态的时候会阻塞在一个条件变量上,除非调用 SuspendAll 的线程接着又调用了 ResumeAll()函数,要不然这些线程就会一直被阻塞住。
4.现在就把 SuspendAll 的流程分析完了,但是 dump 线程堆栈的时候并不是在设置了挂起标志位(KSuspendRequest)后执行的,与他相关的是另外一个标志位 KCheckpointRequest,接下来看一下 Thread_list 的 Dump 函数,这个函数会在 Thread_list 的 DumpForSigQuit 中会被调用到,也就是在 Signal Cathcer 线程处理 SIGQUIT 信号的过程中。
这个函数先创建了一个叫 DumpCheckPoint 对象 checkpoint,然后调用了 RunCheckpoint 将这个对象传入,这个函数会返回现在处于 Runnable 状态的线程个数,接着调用了 WaitForThreadsToRunThroughCheckpoint()等待这些处于 Runnable 的线程都执行完 DumpCheckpoint 的 Run 函数,如果等待超时就会报错。
版权声明: 本文为 InfoQ 作者【北洋】的原创文章。
原文链接:【http://xie.infoq.cn/article/ba980b7e065e09c62434a1d45】。文章转载请联系作者。
评论