打造一款支持线上抓 systrace 的框架

简介: 打造一款支持线上抓 systrace 的框架

1、缘起


缘起是看到网易云音乐技术团队发布的一篇《systrace 统计方法耗时》的文章,文章讲解了如何通过 hook 的方式将 trace 开关打开,并实现不依赖 PC 开启 Trace 功能,实现线上抓取。 文章思路与流程非常清晰,是一个不错的实践(造轮子)机会,我将此文转发给正在研究 xcrash 和 xhook 的同事,我俩一拍即合,打算利用这个机会撸一个框架,并且,同事还给我发了一篇更全面的实践文章《抖音 Android 性能优化系列:新一代全能型性能分析工具 Rhea》,Rhea 经历过三次演进,我们将这些思路进行整合,开发出了一款属于我们自己的框架  Lancer。


我们非常建议,在阅读这款框架源码的时候,一定要看下上述提到的两篇文章。


为什么我们也想做一个:


  • 脱离 PC 抓取 trace 可以帮助我们更好的定位问题,有很多 bug 我们是无法从自己的机型和环境进行复现的,往往需要客户配合来抓取一些日志来实现问题定位,并且,相比较我们自己埋点的日志来说,systrace 采集到的信息更丰富

2、能学到什么?


  • Gradle Transfrom 被废弃,学习使用最新的 TransfromAction
  • 利用 AsmClassVisitorFactory 实现方法插桩
  • 学会使用 xhook 来 hook native 函数
  • 使用 mmap 来优化 IO 性能问题

3、开发的过程中遇到了哪些问题?


插桩方法未正确闭合:

  • try catch 中的 catch 块,需要插桩方法结束标记
  • 在参考字节的 Reha 第一版时,Reha 有限制调用栈深度,所以,我们直接使用了 Stack 集合 size 为 6 来限制层级,以此来提高性能,但忘了考虑多线程调用的问题,故修复后使用 ThreadLocal 来为每个线程保存一份 Stack 来记录方法调用栈深度问题。但在 Rhea 的第三次改造中,Rhea 为了获得更丰富的信息,已取消层级限制。

4、还有哪些不足


  • 插桩方法使用的 class name 和 method name,可以考虑像 Matrix 那样,通过 method Id 来做,然后生成一份 method 映射表。但这么做的话,对于生成的 systrace 可能不太直观, 因为倒入 perfetto 的时候看到的都是 methid Id,可以做一个脚本,读取 systrace 内容,将 method id 拿到,然后通过映射表,恢复方法名,然后再重新写入 systrace,导入 perfetto 查看。Reha 考虑线下用户的易用性,在线下模式打包阶段直接插入的方法名
  • 目前仅在线下使用,理由与 Rhea 一致:

目前 Trace 工具更多的还是在线下使用,由于插桩过多影响了包大小,使得我们线上部分只能对小规模的用户群体定向打开,没法全量上线定位线上大规模用户的性能问题

5、使用


由于放置在 github 的源码没有对外发布依赖,故这里就介绍下如何使用,我相信,如果有同学对这方面有兴趣的话,这一定难不倒他(主要是我们太懒了,笑哭)。

由于 github 项目使用的是复合构建引入的插件模块,如果想接入到自己项目的话,可以参考 setting.gradle,通过 includebuild 来引入插件模块。


在 app 模块的 build.gradle 中使用 tracePlugin 插件:


plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'tracePlugin'
}
trace {
    pkg = "com.bomber.strace"
    ignoreClass = [
        "com.bomber.strace.*.bean.*",
        "com.bomber.*.R",
        "com.bomber.*.R\\\$.*",
        "com.bomber.*.BuildConfig",
    ]
}
复制代码
  • tracePlugin 插件支持 pkg 配置要插桩的包路径,这非常友好,对于一些三方模块,我们暂时没必要对其进行插桩,我们只定位业务模块发生的问题
  • tracePlugin 插件还支持 ignoreClass 来忽略掉一些不需要对其插桩的类,例如 javaBean 和 R 类等,类路径支持正则匹配


在 Application 中对其进行初始化:


class LancerApp : Application() {
    override fun attachBaseContext(base: Context?) {
        super.attachBaseContext(base)
        installLancer()
    }
    private fun installLancer() {
        val traceDir = filesDir.absolutePath + File.separator + "trace"
        val r = Lancer.getInstance().initialize(
            Build.VERSION.SDK_INT,
            traceDir,
            BuildConfig.DEBUG
        )
        Log.d("TraceApp", "r = $r")
    }
}
复制代码


initialize 方法需要传入三个参数:


  • 获取 Android SDK 版本
  • trace 文件存储目录,存储  trace 文件时使用
  • 是否为 debug 环境,打印日志时使用


在需要记录 trace 日志和关闭 trace 日志的地方进行记录:


Lancer.getInstance().start()
Lancer.getInstance().stop()
复制代码


示例 demo 中演示的是从 application 的 attachBaseContext 就开启 start 日志记录,对于想记录业务模块的话,可自由搭配记录位置。


运行 demo 时,需要在 local.properties 下配置下 ndk 路径,如:


ndk.dir=/Users/mac/Library/Android/sdk/ndk/25.1.8937393

release 包效果:


网络异常,图片无法展示
|

  • 打出 release 包,install 安装,并启动应用
  • 结束应用,导出存储在 sd 卡外置存储目录的 trace 文件

perfetto 效果:

image.png

  • 打开 perfetto ui 网址,将导出的 trace 文件直接拖进即可查看
相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
目录
相关文章
|
2月前
|
人工智能 小程序 前端开发
又一个 AI 新项目完结,用 DeepSeek 搞了个微信小程序!
手把手带你用 AI 编程做出一个能上线传播、能变现的微信小程序产品!最新 AI Agent 应用开发 + Vibe Coding 项目,秋招简历亮点拉满~
353 0
|
3月前
|
机器学习/深度学习 人工智能 资源调度
银行零售信贷AI实践:从尽调到贷后的全链路Skill化
信贷审批的本质不是批不批,而是还得起多少。本文详解等额本息与提前还款的算法实现,构建WOE+IV值信用评分模型实现自动审批,用RFM+K-Means聚类完成零售客户分层,设计基于余弦相似度+TopN的产品推荐和AUM增长测算,实现马科维茨投资组合优化和退休规划AI推演引擎。附带7大维度完整性检查清单。
|
3月前
|
人工智能 安全 前端开发
Harness Engineering实战:用AGENTS/ARCHITECTURE规范AI编码Agent全流程
Harness Engineering(驾驭/护栏工程)是一套围绕自主AI Agent构建完整执行环境的工程方法论,不止局限于提示词与上下文优化,还包含标准化工具集、强约束规则、校验闭环、自我修正反馈机制,让AI智能体在生产环境稳定运行,大幅降低幻觉、逻辑错误、架构偏离问题。本文基于企业内部RAG+微调AI平台落地案例,完整拆解通过AGENTS.md、ARCHITECTURE及配套分层规范文档管控编码Agent的整套落地流程,形成可追溯、可审计、防幻觉的开发体系。
583 1
|
缓存 JavaScript 前端开发
Android WebView常见问题
本文主要介绍了在Android开发中WebView的使用方法,包括加载网址、设置相关属性(如JavaScript支持、缓存模式、屏幕适配等)、监听网页加载过程以及返回上一页面的功能实现。同时针对Android P版本限制明文流量的问题(ERR_CLEARTEXT_NOT_PERMITTED),提供了在`AndroidManifest.xml`中添加`android:usesCleartextTraffic="true"`的解决办法。文章还附有完整代码示例,帮助开发者快速上手并解决常见问题。希望对您的开发工作有所帮助!
1055 1
|
4月前
|
Linux 数据库 数据安全/隐私保护
Odoo Docker 部署实战:中小企业 ERP 系统快速上线
不少中小企业都有这样的困扰:销售靠Excel记账、库存人工盘点、财务对账耗时费力、客户信息零散混乱,多个办公系统切换使用,数据不通、效率低下。今天给大家分享一套零成本、一体化的解决方案——Odoo开源ERP系统。全程采用Docker部署,无需复杂环境配置,10分钟即可搭建完成,适配国内服务器,稳定高速、无冗余操作。
448 0
Odoo Docker 部署实战:中小企业 ERP 系统快速上线
|
4月前
|
传感器 JavaScript 芯片
24V转5V/3.3V降压芯片,LDO和DC-DC如何选择
本指南详解24V转5V/3.3V电源方案选型,涵盖PW系列LDO(如PW6206)与DC-DC芯片(PW2312/PW2330等),针对大压差下的效率、散热、噪声、成本等核心挑战,提供“DC-DC主降+LDO后稳”等三级架构建议,助力高效可靠设计。
1230 1
|
4月前
|
存储 人工智能 BI
从0到1搭建智能随访平台:微服务分层设计及多渠道随访执行
医院随访系统是医疗机构延伸院后服务的信息化平台,对接HIS、EMR等系统,支持智能任务调度、多渠道随访、异常预警及数据统计,覆盖全病种、全周期,助力医疗服务闭环与科研管理。
408 0
|
消息中间件 监控 算法
让 nativePollOnce 不再排名第一 | 钉钉 ANR 治理最佳实践
让 nativePollOnce 不再排名第一 | 钉钉 ANR 治理最佳实践
2782 0
让 nativePollOnce 不再排名第一 | 钉钉 ANR 治理最佳实践
|
Java 关系型数据库 数据库连接
【C 言专栏】C 语言与数据库的连接与操作
【5月更文挑战第2天】本文探讨了C语言如何连接和操作数据库,介绍了数据库连接的基本原理,如通过ODBC、JDBC或原生接口与数据库交互。文章详细阐述了使用ODBC连接的步骤,并列举了C语言在数据库操作中的常见任务,强调了错误处理、数据类型匹配和性能优化的重要性。通过实际案例,展示了在学生信息管理系统中应用C语言与数据库交互的过程。本文旨在帮助读者更好地理解和应用C语言进行数据库管理。
640 2