由于工作需要,需要解决一些性能问题,虽然有 Profiler 、Systrace 等工具, 但是无法实时监控,于是计划写一个能实时监控性能的小工具,经过学习大佬们的文章, 最终完成了这个开源的性能实时检测库 。初步能达到预期效果,这里做个记录,算是小结了 。这个性能检测库,可以检测以下问题
- UI 线程 block 检测
- App 的 FPS 检测
- 线程和线程池的创建和启动监控
- IPC(进程间通讯)监控
- 实时通过 logcat 打印问题
- 高效保存检测信息到本地
- 提供上报到指定服务器接口
dependencies {debugImplementation "com.xander.performance:perf:0.1.9"releaseImplementation "com.xander.performance:perf-noop:0.1.9"}
2 APP 工程的 Application 类新增类似如下初始化代码private void initPerformanceTool(Context context) {PERF.Builder builder = new PERF.Builder().globalTag("p-tool") // 全局 log 日志 tag ,可以快速过滤日志.checkUI(true, 100) // 检查 ui 线程, 超过指定时间还未结束,会被认为 ui 线程 block.checkThread(true) // 检查线程和线程池的创建.checkFps(true) // 检查 Fps.checkIPC(true) // 检查 IPC 调用.issueSupplier(new PERF.IssueSupplier() {@Overridepublic long maxCacheSize() {// issue 文件缓存的最大空间return 1024 * 1024 * 20;}@Overridepublic File cacheRootDir() {// issue 文件保存的根目录return getApplicationContext().getCacheDir();}@Overridepublic boolean upLoad(File file) {// 上传入口,返回 true 表示上传成功return false;}}).build();PERF.init(builder);}
原理介绍- UI 线程 block 检测原理
但是这个方案有一个缺点,就是无法处理 InputManager 的输入事件,比如 TV 端的遥控按键事件 。通过按键事件的调用方法 链进行分析,最终每个按键事件都调用了 DecorView 类的 dispatchKeyEvent 方法,而非 Looper 的 loop Message 流程 。所以 AndroidPerformanceMonitor 库是无法准确监控 TV 端应用的耗时情况 。针对 TV 端应用按键处理, 需要找到一个新的切入点,这个切入点就是刚刚的 DecorView 类的 dispatchKeyEvent 方法 。那如何介入 DecorView 类的 dispatchKeyEvent 方法呢?我们通过 epic 库来 hook 这个方法的调用,hook 成功后,我们可以在 DecorView 类的 dispatchKeyEvent 方法调用前后都接收到一个回调方法,在 dispatchKeyEvent 方法调用前我们可以在异步线程执行 一个延时任务,在 dispatchKeyEvent 方法调用后,取消这个延时任务 。如果 dispatchKeyEvent 方法耗时时间小于 指定的时间阈值,可以认为没有 block ,此时移除了延时任务 。如果 dispatchKeyEvent 方法耗时时间大于指定的时间阈值 说明此事 UI 线程是有 block 的,此时,就会执行这个延时任务来收集必要的信息 。
以上就是 UI 线程 block 的检测原理了,目前做得还比较粗糙,后续可以考虑参考 AndroidPerformanceMonitor 打印 CPU 、内存等更多的信息 。
最终终端 log 打印效果如下:
com.xander.performace.demo W/demo_Issue: =================================================type: UI BLOCKmsg: UI BLOCKcreate time: 2021-01-13 11:24:41trace:JAVA.lang.Thread.sleep(Thread.java:-2)java.lang.Thread.sleep(Thread.java:442)java.lang.Thread.sleep(Thread.java:358)com.xander.performance.demo.MainActivity.testANR(MainActivity.kt:49)java.lang.reflect.Method.invoke(Method.java:-2)androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:397)android.view.View.performClick(View.java:7496)android.view.View.performClickInternal(View.java:7473)android.view.View.access$3600(View.java:831)android.view.View$PerformClick.run(View.java:28641)android.os.Handler.handleCallback(Handler.java:938)android.os.Handler.dispatchMessage(Handler.java:99)android.os.Looper.loop(Looper.java:236)android.app.ActivityThread.main(ActivityThread.java:7876)java.lang.reflect.Method.invoke(Method.java:-2)com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656)com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967)复制代码
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 为什么选朱厚熜做皇帝 朱厚璁后下一个皇帝
- 10 个冷门但又非常实用的 Docker 使用技巧
- 每个软件架构师和软件工程师都必须知道的10种设计模式
- 《大盗贼》?我是一个大盗贼什么也不怕
- airpods pro一个耳朵有声音一个耳朵没声音但可以操控,airpodspro一个耳朵有声音一个耳朵没声音-
- nova6se对比荣耀20s?荣耀20和nova6se哪个好_1
- libresse卫生巾感受?libresse薇尔卫生巾怎么样
- 良心推荐8个安全测试工具,快来取走
- 清朝八旗是哪八旗,哪个旗的地位更高? 八旗地位最高的是哪一旗
- 端口的作用