news 2026/6/10 4:01:10

Android 工程接入 TraceFix:编译期自动插桩,Perfetto 直看方法耗时

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android 工程接入 TraceFix:编译期自动插桩,Perfetto 直看方法耗时

序言

推荐一个工具,可以在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 数据」,不负责采集。采集仍需atraceperfetto或 Perfetto UI。


版本怎么选

TraceFix 有两条版本线(见官方 README):

版本线适用场景Artifact
0.1.xAGP 7.4 ~ 8.xio.github.gracker:TraceFix:0.1.0
0.2.xAGP 9.1+、Android 17 新基线io.github.gracker:TraceFix:0.2.0

本文工程环境:

  • AGP 8.13
  • Gradle 8.13
  • compileSdk / targetSdk 37

因此选用0.1.0。若后续升级到 AGP 9.1+,再切0.2.x并可用traceFix {}做更细粒度配置。


接入步骤

1. 在gradle.properties增加开关

prop_traceFixVersion=0.1.0 prop_traceFixEnabled=true prop_traceFixDebugOnly=true
属性含义
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}"){changing=true}}}

注意:若google()/mavenCentral()在内网环境有 SSL 或访问问题,可改为使用公司 Maven 镜像,确保能解析io.github.gracker:TraceFix


3. 新建tracefix.gradle(插件应用逻辑)

放在工程根目录,与build.gradle同级:

deftraceFixEnabled=project.hasProperty('prop_traceFixEnabled')&&prop_traceFixEnabled.toBoolean()if(!traceFixEnabled){return}deftaskNames=gradle.startParameter.taskNames.collect{it.toLowerCase()}defdebugOnly=!project.hasProperty('prop_traceFixDebugOnly')||prop_traceFixDebugOnly.toBoolean()if(debugOnly&&!taskNames.isEmpty()){defbuildsReleaseLike=taskNames.any{it.contains('release')||it.contains('coverage')}defbuildsDebug=taskNames.any{it.contains('debug')}if(buildsReleaseLike&&!buildsDebug){println("[TraceFix] skip${project.path}, tasks=${taskNames}")return}}apply plugin:'auto-add-systrace'println("[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

说明插桩已写入字节码。源码里不会出现这些调用,这是正常的。


如何抓 trace

TraceFix 插桩后,需用系统工具采集。示例(包名已脱敏):

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 中:

  1. 找到进程com.example.myapp
  2. 展开对应线程的时间线
  3. 查找带方法名 + hash 后缀的 slice(TraceFix 命名规则)

为什么建议只开 Debug

构建类型是否插桩原因
Debug本地性能分析
Release避免体积、性能、流水线包受影响
Coverage / 专用测试变体与插桩无关,保持构建纯净

通过prop_traceFixDebugOnly=true+tracefix.gradle的任务名判断实现,无需改业务代码。

若希望 Release 本地包也能 trace,设prop_traceFixDebugOnly=false即可(不建议用于正式发布)。


常见问题

Q1:Debug 包了,Perfetto 还是看不到自己的方法?

按顺序排查:

  1. 是否 clean 全量重编?library 模块未重编会沿用旧产物
  2. 业务模块是否都挂了 TraceFix?只插app往往不够
  3. 采集命令是否包含app类别?
  4. 是否加了-a 你的包名
  5. 是否在源码里找Trace.beginSection应在字节码 / Perfetto 里看

Q2:编译出现 D8 警告Expected stack map table

TraceFix 插桩后偶发,多数情况下WARNING 不影响trace 采集与运行。若变成 ERROR 再针对性处理。

Q3:和 btrace 3.0 怎么选?

TraceFixbtrace 3.0
原理编译期插桩运行时 Hook + 同步抓栈
改源码不需要需在Application.attachBaseContextRheaTrace3.init()
Android 15+可用官方已知:对象分配 Hook 在 15+ 不生效,易出现空 trace
方法覆盖可插桩的方法较全主要在对象创建、锁等抓栈点

高版本 Android(API 35+)上做启动分析,TraceFix 往往更稳妥。

Q4:内网拉不到 TraceFix 依赖?

  • 确认 Maven 镜像已代理 Maven Central
  • 不要把google()放在buildscript最前导致 SSL 失败
  • 可手动确认:io.github.gracker:TraceFix:0.1.0是否在镜像中存在

最小接入清单(Checklist)

  • gradle.properties配置版本与开关
  • build.gradle添加classpath
  • 新建tracefix.gradle
  • subprojects挂到所有业务 library + app
  • clean后编 Debug 包
  • javap确认Trace.beginSection存在
  • atrace采集时带-aapp
  • Perfetto UI 分析

参考链接

  • TraceFix 仓库:https://github.com/Gracker/TraceFix
  • 中文 README:README_zh.md
  • Perfetto UI:https://ui.perfetto.dev

使用网页版抓取trace注意事项

要配置抓取的包名。

验证
查看生成的参数

要有这个

效果

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 3:59:35

旋转座舱技术深度剖析|全网独家复现座椅电控锁止算法、多档位角度精准控制、助力智能座舱空间重构与多场景量产落地

目录 一、行业前言:汽车竞争进入座舱空间争夺战,旋转座舱成核心壁垒 二、技术壁垒拆解:原厂量产旋转座舱三大核心硬核能力 2.1 高精度耐久机械结构,适配全生命周期用车场景 2.2 整车CAN总线联动电控系统(核心壁垒) 2.3 整车被动安全体系重构,适配多角度坐姿 三、量…

作者头像 李华
网站建设 2026/6/10 3:54:28

网络的管理

1、用nmcli c 新增一个名为ens201的连接,该连接的IP等网络参数(eg:ip获取的方式、dns、网关、IP地址)是自动获取的。新增一个名为ens203的连接,该连接的IP等网络参数(eg:ip获取的方式、dns、网关、IP地址)是手动设置的。2、用nmtui 新增一个名为ens202的…

作者头像 李华
网站建设 2026/6/10 3:49:55

【Doris从0到1】(二)Docker部署

第 1 步(1/3):下载启动脚本 #!/bin/bash# Default version DORIS_QUICK_START_VERSION"latest"# Parse parameters while getopts "v:" opt; docase $opt inv) DORIS_QUICK_START_VERSION"$OPTARG";;\?) echo…

作者头像 李华
网站建设 2026/6/10 3:46:24

鸿蒙数学108篇 第六十八篇:平面坐标系完整构建

第六十八篇:平面坐标系完整构建 【阶位归属】第七阶・七星・动态变化篇 【本源溯源】 承接第六十七篇七星与周期数理关联,空间方位、周期节律已然明晰,为精准标定动态点位、描摹运动轨迹,依托两仪阴阳、三才位次、六合方位,构建平面坐标系。坐标系以中和原点为枢,双向…

作者头像 李华
网站建设 2026/6/10 3:46:19

文件描述符(File Descriptors, 简称 FD)

文章目录文件描述符(file descriptor,简称 fd)本质上就是:操作系统给“已打开资源”分配的一个编号。非负整数分配编号后,后续操作就是围绕这个编号来的。代码通常不直接用 fd 编号;真正直接使用 fd 编号的…

作者头像 李华