
序言推荐一个工具可以在apk编译的时候给每个方法添加 trace。项目地址https://github.com/Gracker/TraceFix使用方法https://androidperformance.com/2021/09/13/android-systrace-Responsiveness-in-action-2/还有一个项目也可以使用。字节跳动的。https://github.com/bytedance/btrace/blob/master/README.zh-CN.md接入tracefix 指南Android 工程接入 TraceFix编译期自动插桩Perfetto 直看方法耗时本文记录在一个多模块 Android 系统应用里接入 TraceFix 的完整流程。场景启动优化、录屏/相机等多模块工程希望在不改业务源码的前提下给方法自动加上Trace.beginSection/endSection配合 Perfetto 分析耗时。文中工程名、包名、模块名均已脱敏。TraceFix 是什么TraceFix 是一个编译期字节码插桩Gradle 插件。它会在方法前后自动插入成对的android.os.Trace.beginSection(...);// ... 原方法逻辑 ...android.os.Trace.endSection();这些 slice 会出现在 Perfetto / systrace 的app类别里。它只负责「让 App 产生 trace 数据」不负责采集。采集仍需atrace、perfetto或 Perfetto UI。版本怎么选TraceFix 有两条版本线见官方 README版本线适用场景Artifact0.1.xAGP 7.4 ~ 8.xio.github.gracker:TraceFix:0.1.00.2.xAGP 9.1、Android 17 新基线io.github.gracker:TraceFix:0.2.0本文工程环境AGP 8.13Gradle 8.13compileSdk / targetSdk 37因此选用0.1.0。若后续升级到 AGP 9.1再切0.2.x并可用traceFix {}做更细粒度配置。接入步骤1. 在gradle.properties增加开关prop_traceFixVersion0.1.0 prop_traceFixEnabledtrue prop_traceFixDebugOnlytrue属性含义prop_traceFixEnabled总开关false时完全不插桩prop_traceFixDebugOnlytrue时仅 Debug 变体插桩Release/CI 包不受影响prop_traceFixVersion插件版本便于统一升级2. 根工程build.gradle引入插件在buildscript.dependencies中添加buildscript{repositories{// 能访问 Maven Central 即可企业内网可用镜像仓库mavenCentral()google()// ... 其他已有仓库 ...}dependencies{// ... 已有 classpath ...classpath(io.github.gracker:TraceFix:${prop_traceFixVersion}){changingtrue}}}注意若google()/mavenCentral()在内网环境有 SSL 或访问问题可改为使用公司 Maven 镜像确保能解析io.github.gracker:TraceFix。3. 新建tracefix.gradle插件应用逻辑放在工程根目录与build.gradle同级deftraceFixEnabledproject.hasProperty(prop_traceFixEnabled)prop_traceFixEnabled.toBoolean()if(!traceFixEnabled){return}deftaskNamesgradle.startParameter.taskNames.collect{it.toLowerCase()}defdebugOnly!project.hasProperty(prop_traceFixDebugOnly)||prop_traceFixDebugOnly.toBoolean()if(debugOnly!taskNames.isEmpty()){defbuildsReleaseLiketaskNames.any{it.contains(release)||it.contains(coverage)}defbuildsDebugtaskNames.any{it.contains(debug)}if(buildsReleaseLike!buildsDebug){println([TraceFix] skip${project.path}, tasks${taskNames})return}}apply plugin:auto-add-systraceprintln([TraceFix] applied${project.path}, tasks${taskNames})设计意图本地 / IDE Sync任务列表为空→ 启用方便开发assembleXxxDebug→ 启用纯assembleXxxRelease、流水线任务 → 跳过避免污染正式包4. 在根build.gradle批量挂到业务模块多模块工程里业务代码往往在library而非app。只对真正包含业务逻辑的模块插桩deftraceFixModules[app,core,// 原 common 模块feature-main,// 原 floatwindow 模块feature-media,// 原 av 模块feature-settings,feature-alert,compat-impl,]subprojects{sub-if(!traceFixModules.contains(sub.name)){return}sub.pluginManager.withPlugin(com.android.application){sub.apply from:rootProject.file(tracefix.gradle)}sub.pluginManager.withPlugin(com.android.library){sub.apply from:rootProject.file(tracefix.gradle)}}常见坑只给app模块加插件而app几乎没有业务代码 → Perfetto 里看不到自己的方法。务必覆盖实际承载逻辑的 library。5. 编译验证./gradlew clean :app:assembleDomesticDebug构建日志中应出现[TraceFix] applied :feature-main, tasks[...] [INFO][TraceFixPlugin]register official class instrumentation for project: :feature-main [INFO][TraceFixPlugin]instrumentation registered for variant: domesticDebug用javap抽查某个业务类类名已脱敏javap-c\feature-main/build/intermediates/classes/.../MyApplication.class\|grepTrace期望输出invokestatic #xxx // Method android/os/Trace.beginSection:(Ljava/lang/String;)V invokestatic #xxx // Method android/os/Trace.endSection:()V说明插桩已写入字节码。源码里不会出现这些调用这是正常的。如何抓 traceTraceFix 插桩后需用系统工具采集。示例包名已脱敏adb shell atrace-b65536-t15\-acom.example.myapp\sched am wm gfx view binder_driver dalvik app参数说明参数作用-b 65536buffer 64MB减少数据被覆盖-t 15采集 15 秒-a com.example.myapp只采该 App 的 App 侧 trace过滤其他应用sched am wm ...系统类别CPU 调度、Activity、窗口、渲染、Binder 等app必选TraceFix 的beginSection走这个类别为什么需要-a不加-a所有应用的apptrace 都会进来难以定位加-a只保留目标包名的方法 slice和 TraceFix 配合更清晰推荐操作节奏# 1. 安装 Debug 包带 TraceFix 插桩adbinstall-rapp-domestic-debug.apk# 2. 可选冷启动adb shell am force-stop com.example.myapp# 3. 执行 atrace立刻在手机上复现场景如启动功能、点按钮adb shell atrace-b65536-t15-acom.example.myapp sched am wm gfx view binder_driver dalvik app# 4. 用 Perfetto UI 打开输出文件# https://ui.perfetto.dev在 Perfetto 中找到进程com.example.myapp展开对应线程的时间线查找带方法名 hash 后缀的 sliceTraceFix 命名规则为什么建议只开 Debug构建类型是否插桩原因Debug✅本地性能分析Release❌避免体积、性能、流水线包受影响Coverage / 专用测试变体❌与插桩无关保持构建纯净通过prop_traceFixDebugOnlytruetracefix.gradle的任务名判断实现无需改业务代码。若希望 Release 本地包也能 trace设prop_traceFixDebugOnlyfalse即可不建议用于正式发布。常见问题Q1Debug 包了Perfetto 还是看不到自己的方法按顺序排查是否 clean 全量重编library 模块未重编会沿用旧产物业务模块是否都挂了 TraceFix只插app往往不够采集命令是否包含app类别是否加了-a 你的包名是否在源码里找Trace.beginSection应在字节码 / Perfetto 里看Q2编译出现 D8 警告Expected stack map tableTraceFix 插桩后偶发多数情况下WARNING 不影响trace 采集与运行。若变成 ERROR 再针对性处理。Q3和 btrace 3.0 怎么选TraceFixbtrace 3.0原理编译期插桩运行时 Hook 同步抓栈改源码不需要需在Application.attachBaseContext调RheaTrace3.init()Android 15可用官方已知对象分配 Hook 在 15 不生效易出现空 trace方法覆盖可插桩的方法较全主要在对象创建、锁等抓栈点在高版本 AndroidAPI 35上做启动分析TraceFix 往往更稳妥。Q4内网拉不到 TraceFix 依赖确认 Maven 镜像已代理 Maven Central不要把google()放在buildscript最前导致 SSL 失败可手动确认io.github.gracker:TraceFix:0.1.0是否在镜像中存在最小接入清单Checklistgradle.properties配置版本与开关根build.gradle添加classpath新建tracefix.gradlesubprojects挂到所有业务 library appclean后编 Debug 包javap确认Trace.beginSection存在atrace采集时带-a和appPerfetto UI 分析参考链接TraceFix 仓库https://github.com/Gracker/TraceFix中文 READMEREADME_zh.mdPerfetto UIhttps://ui.perfetto.dev使用网页版抓取trace注意事项要配置抓取的包名。验证查看生成的参数要有这个效果