前言

首先收集需要dump trace的进程并给对应进程发送dump trace的信号

1.当一些带有超时机制的系统消息(如:service的创建)判定超时后,会调用系统服务ams接口,收集anr相关信息并存档(data/anr/trace, data/system/dropbox)

2.进入到ams中,apperror会先进行筛选(1.当前进程正在进行dump流程 2.已经发生crash 3. 已经被系统kill 4.系统是否正在关机等情况),如果都不符合,则认为当前进程发生了anr。

3.接下来系统在判断当前anr进程对用户是否可感知,然后开始统计与该进程由关联的进程,或者一些系统核心服务进程的信息(例如与应用交互的surfacefligner,system server等系统进程),如果这些系统服务进程在响应时被阻塞,那么将导致应用进程ipc通信过程被卡死。接着获取其他系统核心进程,因为这些服务进程是init进程直接创建的,并不在systemserver或zygote进程管理范围。 >firstpids队列:第一个是anr进程,第二个是system_server,剩余是所有persistent进程; native队列:是指/system/bin/目录的mediaserver,sdcard 以及surfaceflinger进程; lastpids队列: 是指mlruprocesses中的不属于firstpids的所有进程。

4.在收集完第一步信息后,接下来便开始统计各进程本地的更多信息,如虚拟机信息,java线程状态及堆栈。首先会弹出一个anr的对话框,然后向ui线程发送show_not_responding_msg消息

5.当ui线程收到该消息后,会调用dumpstacktraces函数:

最重要的一点:向目标进程发送sinal_quit(进程中的signal catcher会进行阻塞检测收集信息后面讲),firstpids列表中的进程, 两个进程之间会休眠200ms, 可见persistent进程越多,则时间越长. top 5进程的traces过程中, 同样是间隔200ms, 另外进程使用情况的收集也是比较耗时.

总结;

>将am_anr信息输出到eventlog(分析anr问题时先看该log) 获取重要进程的信息,java进程的,和native的进程 将anr的reason和cpu使用的情况输出到main_log 在将cpu使用情况和进程的trace文件信息,在保存到drpobox文件下 向收集到的进程发送sinal_quit信号。

接着分析最后一步向收集到的进程发送信号

(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函数,如果等待超时就会报错。

接着分析runcheckpoint函数,先看前一部分:

对于处于runnable状态的线程执行它的requestcheckpoint函数会返回true,其他状态的线程则会返回false。对于这些非runnable状态的线程就会像suspendall一样会设置ksuspendrequest标志位,后面状态切换的时候就会检查这个标志位挂起。同事runcheckpoint函数会把这些线程统计到suspend_count_modified_threads这个vector变量中,在这个变量中的线程,singal catcher线程会主动触发他们的dump堆栈过程。接下来再看看这个requestcheckpoint函数

最后一行设置kcheckpointrequest标志位,在刚才线程切换运行状态时会执行checksuspend函数在检测kcheckpointrequest标志位的时候会执行runcheckpointfunction函数,接着会执行这个checkpoints里面元素的run函数:

(这个存储的其实就是thread中的requestcheckpoint在这里不仅设置了标志位还把参数设置为元素的值,这个参数就是dump里面调用runcheckpoint传过来的,其实就是dumpcheckpoint)。 ,所以也就是执行dumpcheckpoint的run函数:

其实就是调用了thread的dump函数,线程的java堆栈,native堆栈和kernel堆栈就是在这里打印的,刚才说对于处于runnable状态的线程是通过调用他们的requestckeckpoint函数,然后它们自己去dump当前堆栈的,而那些不处于runnable状态的线程则是添加到了一个vector的变量中,接着就分析runcheckpoint函数的第二部分:

对于这些不是runnable状态的线程,他们可能不会主动去调用run函数,所以只能有signal catcher线程去帮他们dump,至于dumpcheckpoint的run函数的功能和runnable状态的线程是一样的,都是打印线程堆栈,并且最后修改引用计数让这些线程在切换状态时继续运行。

总结:

>1.singalcatcher线程接收到信号后,首先dump当前虚拟机有关信息(内存状态。对象,加载class,gc等相关信息) 2.接下来会设置每个线程的标记为(check_point),和请求线程状态(suspend)。当线程运行过程中进行上下文切换时,会检查该标记。如果发现有挂起请求,会将自己主动挂起。等到所有线程都挂起之后,singalcatcher线程开始遍历dump各个线程的堆栈和线程数据后再唤醒线程。如果某个线程一直无法挂起导致超时,那么本次dump流程失败抛出异常.

大致流程(android5.0之前):

checkpoint:

先讲解safepoint,对于art编译的代码,可以定期轮询当前runtime来确认是否需要执行某些特定代码;可以认为这些轮询时的点,就是safepoint;safepoint可以用来实现暂定一个java线程,也可以用来实现checkpoint机制; 例: 当正在执行java代码的线程a执行到safepoint时,会执行checksuspend函数,在发现当前线程有 checkpoint request时, 会在这个点执行线程的checkpoint函数;如果发现当前线程有suspend request时,会进行suspendcheck,使得线程进入suspend状态(暂停); 所以说,art checkpoint应该是safepoint的一个功能实现;

到此这篇关于android anr分析trace文件的产生流程详情的文章就介绍到这了,更多相关android anr分析 内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!

发表评论

后才能评论