线上监控的方案
1、BlockCanary
从Choregrapher中可以知道,帧的渲染是通过消息发送到主线程执行的。所以通过在计算msg的处理时间就可以判定是否发生卡顿。
Looper.java
public static void loop() {
...
for (;;) {
...
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
...
}
}
BlockCanary主要是检测msg.target.dispatchMessage(msg);
之前的>>>>> Dispatching to
和之后的<<<<< Finished to
的间隔时间。 应用发生卡顿,一定是在dispatchMessage中执行了耗时操作。通过给主线程的Looper设置一个Printer,打点统计dispatchMessage方法执行的时间,如果超出阀值,表示发生卡顿,则dump出各种信息,提供开发者分析性能瓶颈。
2、Matrix
帧率监控
向 Choreographer 注册监听,在每一帧 doframe 回调时判断距离上一帧的时间差是否超出阈值(卡顿),若是超出阈值,则获取数组 index 前的全部数据(即两帧之间的全部函数执行信息)进行分析上报。
慢函数,Anr监控
和BlockCannary一样是通过Looper的printer获取msg的执行时间
Matrix还对方法进行了插桩,对每个方法可以更详细的分析
线下工具
1、Perfetto
Perfetto是基于Android 9(P)起可用的平台级跟踪工具,但仅从Android 11(R)起默认启用。在Android 9(P)和10(Q)上,我们首先需要开启traced和traced_probes这两个进程,才能使用Perfetto来抓取数据,可通过命令行来开启手机的这两个进程
adb shell setprop persist.traced.enable 1
在开发者选项中打开
-
命令行工具抓取
adb shell perfetto --config :test --out /data/misc/perfetto-traces/trace
查看
在Chrome打开 https://ui.perfetto.dev/#!/
2、Systrace
命令行:systrace.py -t 10 sched gfx view wm am app webview -o mytrace.html -a com.androidtrace.test
具体参数含义如下:
- -t:指定统计时间为20s。
- shced:cpu调度信息。
- gfx:图形信息。
- view:视图。
- wm:窗口管理。
- am:活动管理。
- app:应用信息。
- webview:webview信息。
- -a:指定目标应用程序的包名。
- -o:生成的systrace.html文件。
查看丢帧
查看主线程状态
绿色:运行状态
橙色:IO阻塞
蓝色:系统资源不足
灰色:锁
紫色:频繁创建对象
3、Profiler
Profiler查看函数耗时非常方便,缺点是开销大,可能带偏方向
Call Chart可以清晰的看到具体的方法调用情况和执行时间
Bottom Up根据方法耗时排序
4、TraceView
TraceView需要手动埋点,生成的trace文件,路径在sdcard/Android/data/项目包名/files。拿到trace文件后用profiler分析和上面是一样的
//开始埋点,“app”是最后生成的性能分析文件
Debug.startMethodTracing("App");
//埋点结束,期间start 到 stop 之间的代码,就是你要测试的代码范围
Debug.stopMethodTracing();
5、StrictMode
线程策略的检测内容,是一些自定义的耗时调用、磁盘读取操作以及网络请求等。
虚拟机策略的检测内容:Activity泄露,Sqlite泄露,检测实例数量
// 设置线程策略
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectCustomSlowCalls() //API等级11,使用StrictMode.noteSlowCode
.detectDiskReads()
.detectDiskWrites()
.detectNetwork() // or .detectAll() for all detectable problems
.penaltyLog() //在Logcat 中打印违规异常信息
// .penaltyDialog() //也可以直接跳出警报dialog
// .penaltyDeath() //或者直接崩溃
.build());
//设置虚拟机策略
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
// 给NewsItem对象的实例数量限制为1
.setClassInstanceLimit(NewsItem.class, 1)
.detectLeakedClosableObjects() //API等级11
.penaltyLog()
.build());