What is BlockCanary
Android平台的开源主线程性能检测开源库。
Github : https://github.com/markzhai/AndroidPerformanceMonitor
Android如何获取主线程堆栈信息
Thread.getStackTrace()方法。
如何在其他线程获取主线程引用 : Looper.getMainLooper().getThread();
如何Cpu使用情况
获取Cpu总数据,来自CpuSampler的doSample方法
从 /proc/stat 中读取Cpu信息,可参考 http://www.blogjava.net/fjzag/articles/317773.html
执行parse方法,解析相关数据,可以获取到 total, idle, user 等cpu使用情况
获取当前进程的cpu数据,同是doSample方法
进程相关的cpu占用情况,数据取自 "/proc/" + mPid + "/stat" 文件同样通过parse方法进行解析
如何跟踪主线程的时间执行情况
在主线程msg.target.dispatchMessage前后有被打印,两次打印之间的时间差就是这个dispatch 的message所被执行的时间。
如何检测到dispatchMessage前后的log被执行
Looper有一个setMessageLogging可以设置自己的Printer
BlockCanary实现的自定义Printer 为 LooperMonitor,当dispatchMessage前后的log执行的是LooperMonitor的println
从println的代码中,可以知道
dispatchMessage之前的log被打印时,执行的红色部分,即:
- 记录当前的时间戳
- startDump
dispatchMessage之后的log被打印时,执行的绿色部分,即:
- 计算此次消费事件是否block
- 如果block,执行notifyBlockEvent
- stopDump
判断是否block
是否block,就是判断的开始log 与 结束log的时间差是否大于设定的阀值
当block时 , 执行notifyBlockEvent
发生了block时,执行mBlockListener的onBlockEvent方法。HandlerThreadFactory.getWriteLogThreadHandler实际上是返回的新建子线程的hander,也就是说,mBlockListener.onBlockEvent是在子线程进行的一个回调。
mBlockListener.onBlockEvent具体做了什么?我们找到设置的地方
构造器中设置了blockListener,我们找到创建LooperMonitor的地方
onBlockEvent : 我们得知,只有发生block时,才进行LogWriter的保存
- 获取线程堆栈信息
- LogWriter 保存blockInfo
- 通知所有interceptor onBlock.
Printer 的 println方法中如何通过startDump开始收集快照 ,stopDump停止收集快照
LooperMonitor的startDump方法
我们发现stackSampler 和 cpuSampler是 BlockCanaryInternals的成员变量,并且在构造器中进行了初始化
stackSampler 和 cpuSampler的 start方法
主要就是使用一个handler postDelay了一个Runnable对象。关于这个handler对象,我们再看下HandlerThreadFactory的代码
通过上面的代码,我们得知,实际这个handler是一个子线程的handler,也就是开启的一个子线程在xx毫秒后执行Runnable对象的run方法,这个Runnable对象的run方法又做了什么呢?
通过上面的代码可知:
- 执行了doSample(),CpuSampler的doSample采集 cpu , StackSampler的doSample采集 堆栈信息
- 判断是否设置采集为true.
- 循环采样:如果设置采集为true,采样后,继续postDelay一个Runnable对象用于继续采集下一周期。
如何停止收集快照
调用AbstractSampler的stop方法,即设置一个标志位,在循环采样中进行了判断,当标志位为false时,循环采样终止。