原理概述
Android系统中的消息机制是依靠Looper不断从MessageQueue中取出Message进行处理,卡顿的直接原因是处理Message的时间过长,所以监控卡顿主要是监控Message的处理时长。
BlockCanary通过重设Looper中的Printer对象来记录Message的处理时长,当时长超过阀值时即发生卡顿,获取此时的栈和CPU信息供排查原因。
使用
//依赖
debugImplementation 'com.github.markzhai:blockcanary-android:1.5.0'
releaseImplementation 'com.github.markzhai:blockcanary-no-op:1.5.0'
//初始化
BlockCanary.install(this, new BlockCanaryContext()).start();
初始化
BlockCanary的参数设置在BlockCanaryContext类中,通过继承可以修改配置
监控
初始化拿到BlockCanary单例后便开始监控
向MainLooper中设置Printer
Looper在消息处理的过程中会通过Printer打印日志,BlockCanary正是利用了这一点来测量处理Message所耗的时长
Printer对象的初始化在BlockCanaryInternals单例中
Looper通过调用Printer的println来打印日志,BlockCanary的监控必须放在此方法内
当Message处理的时间超过阀值会回调onBlockEvent
栈、CPU信息
识别出了卡顿,接下来就是分析卡顿产生的原因
Message在每次处理时,都会记录栈、CPU信息
栈
StackSampler继承自AbstractSampler,在AbstractSampler内部通过HandlerThread新启线程,利用Handler的postDelayed方法循环取样
取样信息存在LinkedHashMap中
CPU
与StackSampler代码逻辑类似,只不过信息的来源不同了。CpuSampler的信息是通过读取系统log文件的形式获取的,通过解析获取想要的信息组成字符串,存入LinkedHashMap中
信息获取
发生卡顿时,会回调onBlockEvent,四个参数分别表示:记录开始时间点、记录结束时间点、记录开始时间点线程所运行时间、记录结束时间点线程所运行时间
sStackMap中的key是记录的时间点,落在记录开始、结束时间点中间的栈信息都是同一Message处理所产生的
同理获取CPU信息,组装成BlockInfo对象,由LogWriter写入单独文件进行存储
信息展示
之前添加的监听被回调
跳转到信息展示页面DisplayActivity
在页面启动时加载卡顿信息
加载的过程是封装为LoadBlocks的Runnable
获取保存的所有日志文件
转成BlockInfoEx对象
将数据设置到Activity并更新UI