TraceCanary 适配 AGP8 解析
1. 项目背景
本文基于实际的 Matrix TraceCanary 适配 AGP8 项目,深入分析
2. MatrixTracePlugin 核心实现解析
2.1 插件架构设计
class MatrixTracePlugin : Plugin<Project> {
override fun apply(project: Project) {
// 1. 创建扩展配置
val matrix = project.extensions.create("matrix", MatrixExtension::class.java)
val traceExtension = (matrix as ExtensionAware).extensions
.create("trace", MatrixTraceExtension::class.java)
// 2. 验证 Android Application 插件
if (!project.plugins.hasPlugin("com.android.application")) {
throw GradleException("Matrix Plugin, Android Application plugin required.")
}
// 3. 配置日志级别
project.afterEvaluate {
Log.setLogLevel(matrix.logLevel)
}
// 4. 仅配置当前变体
val startParameter = project.gradle.startParameter
val taskNames = startParameter.taskNames.firstOrNull() ?: ""
// 5. 注册 Instrumentation
val androidComponents = project.extensions
.getByType(AndroidComponentsExtension::class.java)
androidComponents.onVariants { variant ->
if (taskNames.contains(variant.name, true)) {
configureVariant(project, variant, traceExtension)
}
}
}
}
关键设计点:
- 使用
AndroidComponentsExtension替代旧的 Transform 注册方式 - 通过
onVariants回调为当前构建变体单独配置 - 延迟配置确保所有依赖项已就绪
2.2 变体配置核心逻辑
private fun configureVariant(
project: Project,
variant: Variant,
extension: MatrixTraceExtension
) {
if (!extension.isEnable) {
Log.i("MatrixTracePlugin", "not enable trace!")
return
}
// 1. 设置 ASM 帧计算模式 COPY_FRAMES 是默认模式,可以不设置,大值会覆盖小值
variant.instrumentation.setAsmFramesComputationMode(
FramesComputationMode.COPY_FRAMES
)
// 2. 注册字节码转换器
variant.instrumentation.transformClassesWith(
MatrixTraceClassVisitorFactory::class.java,
InstrumentationScope.ALL
) { params ->
configureInstrumentationParams(params, project, extension)
}
// 3. 设置方法映射保存任务
setupMappingSaveTask(project, variant)
}
2.3 黑名单处理机制
// 处理黑名单文件的核心逻辑
extension.blackListFile?.let { blockFile ->
if (File(blockFile).exists()) {
val buildDir = project.layout.buildDirectory.get().asFile
val mappingFile = buildDir.resolve("outputs/matrix/mapping/${variant.name}").resolve("methodMapping.txt")
//缓存 兼容: clean后会删除 mappingFile ,此时应该重新走所有插桩流程
// 只改变参数,不参与到具体逻辑,不会打断 增量更新逻辑!!!
// params.cacheFlag.set(mappingFile.exists())params.blockListFilePath.set(project.file(blockFile).absolutePath)
val useCache = mappingFile.exists()
if (!useCache) {
val ct = System.currentTimeMillis()
if (ct % 2 != 0L) {
params.cacheStmp.set(ct - 1)
} else {
params.cacheStmp.set(ct)
}
} else {
params.cacheStmp.set(1L)
}
// 解析黑名单内容
val blockStr = (TraceBuildConstants.DEFAULT_BLOCK_TRACE
+ FileUtil.readFileAsString(project.file(blockFile).absolutePath))
val blockArray = blockStr.trim().replace("/", ".").replace("\r", "")
.split("\n").dropLastWhile { it.isEmpty() }.toTypedArray()
val processor = MappingCollector()
val blockSet = hashSetOf<String>()
for (block in blockArray) {
when {
block.startsWith("-keepclass ") -> {
val className = block.replace("-keepclass ", "")
blockSet.add(processor.proguardClassName(className, className))
}
block.startsWith("-keeppackage ") -> {
val packageName = block.replace("-keeppackage ", "")
blockSet.add(processor.proguardPackageName(packageName, packageName))
}
}
}
params.blockSet.set(blockSet)
//设置本地旧mapping
loadMethodMapping(mappingFile)
}
}
实现特点:
- 支持 ProGuard 风格的配置语法
- 区分类级别和包级别的过滤规则
- 使用
MappingCollector处理混淆映射
2.4 方法映射保存任务
private fun setupMappingSaveTask(project: Project, variant: Variant) {
val variantName = variant.name.capitalize()
val saveMappingTask = project.tasks.register("saveMapping$variantName") { task ->
task.group = "matrix"
task.description = "Save method mapping for $variantName"
task.doLast {
// 检查当前是否正在构建该变体
val isCurrentVariantBuilding = project.gradle.startParameter.taskNames
.any { taskName ->
taskName.contains(variant.name, ignoreCase = true) ||
taskName.contains("assemble${variantName}", ignoreCase = true)
}
if (!isCurrentVariantBuilding) return@doLast
// 保存方法映射文件
val buildDir = project.layout.buildDirectory.get().asFile
val mappingOutDir = buildDir.resolve("outputs/matrix/mapping/${variant.name}")
mappingOutDir.mkdirs()
val mappingFile = mappingOutDir.resolve("methodMapping.txt")
if (mappingFile.exists()) {
mappingFile.delete() // 如果文件存在就删除
}
mappingFile.createNewFile()
saveMethodMapping(mappingFile)
}
}
// 配置任务依赖关系
project.afterEvaluate {
val mappingTask = saveMappingTask.get()
// Transform 任务完成后执行
project.tasks.matching { task ->
task.name.contains("transform")
}.configureEach { transformTask ->
transformTask.finalizedBy(mappingTask)
}
// Assemble 任务依赖映射保存
project.tasks.matching { task ->
task.name.contains("assemble") &&
task.name.contains(variant.name, ignoreCase = true)
}.forEach { assembleTask ->
assembleTask.dependsOn(saveMappingTask)
}
}
}
关键优化:
- 智能检测当前构建变体,避免不必要的任务执行
- 使用新的 Gradle API
project.layout.buildDirectory - 合理的任务依赖关系确保映射文件及时生成
3. MatrixTraceClassVisitorFactory 深度解析
3.1 参数接口设计
interface Params : InstrumentationParameters {
// 缓存占位: 有参数变更会触发全量插桩操作
@get:Input
val cacheStmp: Property<Long>
@get:Input
val packageName: Property<String>
@get:Input
val blockListFilePath: Property<String>
@get:Input
val skipCheckClass: Property<Boolean>
@get:Input
val blockSet: SetProperty<String>
}
注意:
- 使用 Gradle Property API 确保类型安全和缓存支持
@Input注解支持增量构建SetProperty<String>高效处理黑名单集合
3.2 类过滤机制
override fun isInstrumentable(classData: ClassData): Boolean {
var isNeed = true
// 检查类是否在黑名单中
if (parameters.get().blockSet.get().contains(classData.className)) {
isNeed = false
} else {
// 检查包名是否在黑名单中
for (packageName in parameters.get().blockSet.get()) {
if (classData.className.startsWith(packageName.replace("/", "."))) {
isNeed = false
break
}
}
}
// cacheStmp 参与到判断中,用于打断固有的增量 逻辑
if (isNeed && parameters.get().cacheStmp.get() % 2 == 0L) {
insertClassSize.getAndIncrement()
}
return isNeed
}
过滤策略:
- 精确类名匹配优先级最高
- 包名前缀匹配作为补充
- 早期过滤减少后续处理开销
3.3 方法 ID 生成与管理
companion object {
private val methodIdGenerator = AtomicInteger(1)
private val methodMap = ConcurrentHashMap<String, Int>()
fun getOrCreateMethodId(className: String, methodName: String, desc: String): Long {
val signature = "$className.$methodName$desc".replace("/", ".")
return methodMap.computeIfAbsent(signature) {
methodIdGenerator.getAndIncrement()
}
}
fun saveMethodMapping(outputFile: File) {
outputFile.bufferedWriter().use { writer ->
val sortedByValue = methodMap.entries.sortedWith(compareBy { it.value })
sortedByValue.forEach { (signature, id) ->
writer.write("$id,${signature}\n")
}
if (methodMap["message_dispatch_start"] == null) {
// 写入最后一行,标识消息分发开始
writer.write("${0xFFFFF - 1},message_dispatch_start\n")
Log.e(TAG, "saveMethodMapping: ${methodMap.entries.size + 1}")
} else {
Log.e(TAG, "saveMethodMapping: ${methodMap.entries.size}")
}
}
}
//加载本地文件
fun loadMethodMapping(inputFile: File) {
insertClassSize.set(0L)
if (!inputFile.exists()) {
Log.i(TAG, "oldMethodMapping: file not exists!")
return
}
inputFile.bufferedReader().use { reader ->
reader.forEachLine { line ->
val list = line.split(",")
if (list.isNotEmpty()) {
val (id, signature) = list
methodMap[signature] = id.toLong()
}
}
}
methodIdGenerator.set(methodMap.size.toLong() + 1)
Log.i(TAG, "loadMethodMapping: ${methodIdGenerator.get() - 1}")
}
}
3.4 类访问器核心实现
class MatrixTraceClassVisitor(
nextClassVisitor: ClassVisitor,
private val ps: Params
) : ClassVisitor(Opcodes.ASM9, nextClassVisitor) {
private var className: String = ""
private var isActivityOrSubClass = false
private var hasWindowFocusMethod = false
private var isNeedTrace = false
override fun visit(version: Int, access: Int, name: String,
signature: String?, superName: String,
interfaces: Array<String?>?) {
super.visit(version, access, name, signature, superName, interfaces)
this.className = name
this.isActivityOrSubClass = isActivityOrSubClass(className, superName)
this.isNeedTrace = isNeedTrace(ps, className, null)
// 过滤抽象类和接口
if ((access and Opcodes.ACC_ABSTRACT) > 0 ||
(access and Opcodes.ACC_INTERFACE) > 0) {
this.isABSClass = true
}
}
}
3.5 方法插桩核心逻辑
private class TraceMethodVisitor(
private val api: Int,
private val mv: MethodVisitor,
private val access: Int,
private val name: String,
private val desc: String,
private val className: String,
// ... 其他参数
) : MethodVisitor(api, mv) {
private val traceMethod = TraceMethod.create(
getOrCreateMethodId(className, name, desc),
access, className, name, desc
)
override fun visitCode() {
super.visitCode()
insertMethodEnterTrace()
}
override fun visitInsn(opcode: Int) {
// 在所有返回指令前插入退出追踪
if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) ||
opcode == Opcodes.ATHROW) {
insertMethodExitTrace()
}
super.visitInsn(opcode)
}
private fun insertMethodEnterTrace() {
mv.visitLdcInsn(traceMethod.id)
mv.visitMethodInsn(
Opcodes.INVOKESTATIC,
TraceBuildConstants.MATRIX_TRACE_CLASS,
"i", "(I)V", false
)
}
private fun insertMethodExitTrace() {
mv.visitLdcInsn(traceMethod.id)
mv.visitMethodInsn(
Opcodes.INVOKESTATIC,
TraceBuildConstants.MATRIX_TRACE_CLASS,
"o", "(I)V", false
)
}
}
插桩策略:
- 方法入口统一插入
i(methodId)调用 - 所有退出点(包括异常)插入
o(methodId)调用 - 使用方法 ID 而非字符串减少运行时开销
3.6 Activity 特殊处理
private fun isActivityOrSubClass(cN: String, sN: String): Boolean {
return cN == TraceBuildConstants.MATRIX_TRACE_ACTIVITY_CLASS ||
cN == TraceBuildConstants.MATRIX_TRACE_V4_ACTIVITY_CLASS ||
cN == TraceBuildConstants.MATRIX_TRACE_V7_ACTIVITY_CLASS ||
cN == TraceBuildConstants.MATRIX_TRACE_ANDROIDX_ACTIVITY_CLASS ||
cN == TraceBuildConstants.MATRIX_TRACE_ANDROIDX_F_ACTIVITY_CLASS ||
sN == TraceBuildConstants.MATRIX_TRACE_ACTIVITY_CLASS ||
sN == TraceBuildConstants.MATRIX_TRACE_V4_ACTIVITY_CLASS ||
sN == TraceBuildConstants.MATRIX_TRACE_V7_ACTIVITY_CLASS ||
sN == TraceBuildConstants.MATRIX_TRACE_ANDROIDX_ACTIVITY_CLASS ||
sN == TraceBuildConstants.MATRIX_TRACE_ANDROIDX_F_ACTIVITY_CLASS
}
// 插入 onWindowFocusChanged 方法
private fun insertWindowFocusChangeMethod(
cv: ClassVisitor, classname: String, superClassName: String
) {
val methodVisitor = cv.visitMethod(
Opcodes.ACC_PUBLIC,
TraceBuildConstants.MATRIX_TRACE_ON_WINDOW_FOCUS_METHOD,
TraceBuildConstants.MATRIX_TRACE_ON_WINDOW_FOCUS_METHOD_ARGS,
null, null
)
methodVisitor.visitCode()
// 调用父类方法
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0)
methodVisitor.visitVarInsn(Opcodes.ILOAD, 1)
methodVisitor.visitMethodInsn(
Opcodes.INVOKESPECIAL, superClassName,
TraceBuildConstants.MATRIX_TRACE_ON_WINDOW_FOCUS_METHOD,
TraceBuildConstants.MATRIX_TRACE_ON_WINDOW_FOCUS_METHOD_ARGS, false
)
// 插入追踪代码
traceWindowFocusChangeMethod(methodVisitor, classname)
methodVisitor.visitInsn(Opcodes.RETURN)
methodVisitor.visitMaxs(2, 2)
methodVisitor.visitEnd()
}
Activity 优化:
- 兼容多个版本的 Activity 基类
- 自动注入
onWindowFocusChanged方法用于启动耗时统计 - 保持原有方法调用链的完整性
4. AGP8 适配关键技术点
4.1 API 迁移对比
| 特性 | Transform API (旧) | Instrumentation API (新) |
|---|---|---|
| 注册方式 | registerTransform() | transformClassesWith() |
| 参数传递 | Transform 构造函数 | InstrumentationParameters |
| 类过滤 | isIncremental() | isInstrumentable() |
| 处理粒度 | 文件级别 | 类级别 |
| 缓存支持 | 基础支持 | 强化增量构建 |
4.2 性能优化措施
override fun isInstrumentable(classData: ClassData): Boolean {
// 在字节码解析前就过滤掉不需要的类
return !isSystemClass(classData.className)
}
private val methodMap = ConcurrentHashMap<String, Int>()
private val methodIdGenerator = AtomicInteger(1)
override fun visitMaxs(maxStack: Int, maxLocals: Int) {
// 确保栈大小足够容纳插入的指令
super.visitMaxs(maxStack + 4, maxLocals)
}
4.3 构建配置最佳实践
// build.gradle 推荐配置
matrix {
logLevel "D"
trace {
enable = true
blackListFile = "${project.projectDir}/matrixTrace/blackMethodList.txt"
}
}
5. 实际应用效果
5.1 编译时输出
> Task :app:transformClassesWithMatrixTraceForDebug
Matrix.TraceClassVisitorFactory: 实例化.
MatrixTracePlugin: variant:debug
MatrixTraceClassVisitor: 处理类 com/example/MainActivity
MatrixTraceClassVisitor: 插桩方法 onCreate()V
MatrixTraceClassVisitor: 插桩方法 onResume()V
...
> Task :app:mergeAppTestReleaseGeneratedProguardFiles
> Task :app:saveMappingAppDevDebug
> Task :app:saveMappingAppDevRelease
> Task :app:saveMappingAppProDebug
> Task :app:saveMappingAppProRelease
> Task :app:saveMappingAppTestDebug
> Task :app:saveMappingAppTestRelease
[D][MatrixTracePlugin] 开始存储mapping
5.2 方法映射文件示例
...
271272,com.lagos.emobility.driver.ui.underway.google.GoogleNavigationController$initializeNavigationApi$2$1.onError(I)V
271273,com.lagos.emobility.driver.ui.underway.google.GoogleNavigationController.initializeNavigationApi$lambda$1(Lcom.lagos.emobility.driver.ui.underway.google.GoogleNavigationController;Lkotlin.jvm.functions.Function2;)V
271274,com.lagos.emobility.driver.ui.underway.google.GoogleNavigationController.withMapAsync$lambda$2(Lkotlin.jvm.functions.Function1;Lcom.google.android.gms.maps.GoogleMap;)V
1048574,message_dispatch_start
...
5.3 运行时监控数据
// 生成的字节码调用示例
public void onCreate(Bundle savedInstanceState) {
MethodBeat.i(1); // 方法进入
try {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// ... 业务逻辑
} finally {
MethodBeat.o(1); // 方法退出
}
}
6 堆栈解析
6.1堆栈数据格式解析:
原始数据结构
{
"nameValuePairs": {
"machine": "HIGH",
"cpu_app": 0,
"mem": 8055660544,
"mem_free": 3264324,
"detail": "NORMAL",
"cost": 905,
"scene": "com.lagos.emobility.driver.ui.underway.OrderUnderwayActivity",
"stack": "0,1048574,1,905\n1,258336,1,903\n2,20604,1,897\n3,22106,1,186\n4,35700,1,186\n5,21656,1,186\n6,26128,1,181\n7,81196,1,137\n8,23665,1,137\n3,24006,1,603\n4,58165,1,503\n5,22284,1,338\n6,64326,1,338\n7,60162,1,322\n8,60154,1,322\n9,35700,1,162\n10,35723,1,162\n11,35700,1,162\n12,64378,1,162\n13,63526,1,121\n14,65534,1,110\n15,81196,1,110\n16,63398,1,110\n17,35700,1,99\n18,35723,1,99\n19,35700,1,99\n20,64365,1,99\n21,17766,1,84\n9,63491,1,160\n10,63497,1,160\n",
"stackKey": "60154|",
"tag": "Trace_EvilMethod",
"process": "com.lagos.emobility.driver",
"time": 1750662360918
}
}
堆栈格式说明
格式: depth,methodId,count,cost
- depth: 调用深度(0为根调用)
- methodId: 方法唯一标识符
- count: 调用次数
- cost: 耗时(毫秒)
特殊方法ID:
- 1048574 (0xFFFFF-1): message_dispatch_start 消息分发起始点
- 其他ID: 对应 methodMapping.txt 中的方法映射
Js解析脚本
完整解析工具
const fs = require('fs');
function parseStackTrace(mappingFilePath, stackInput) {
try {
// 读取mapping文件
let mapping = {};
if (fs.existsSync(mappingFilePath)) {
const mappingContent = fs.readFileSync(mappingFilePath, 'utf8');
// 解析mapping文件格式: methodId,methodSignature
const lines = mappingContent.trim().split('\n');
lines.forEach(line => {
if (line.trim()) {
const commaIndex = line.indexOf(',');
if (commaIndex > 0) {
const id = parseInt(line.substring(0, commaIndex).trim());
const signature = line.substring(commaIndex + 1).trim();
// 简化方法签名显示
const simplifiedName = simplifyMethodSignature(signature);
mapping[id] = {
full: signature,
simple: simplifiedName
};
}
}
});
console.log(`成功加载 ${Object.keys(mapping).length} 个方法映射`);
} else {
console.log(`Warning: Mapping file ${mappingFilePath} not found`);
}
// 读取堆栈数据(支持文件或字符串)
let stackString;
if (fs.existsSync(stackInput)) {
stackString = fs.readFileSync(stackInput, 'utf8');
console.log(`从文件读取堆栈数据: ${stackInput}`);
} else {
stackString = stackInput;
console.log(`使用传入的堆栈字符串`);
}
// 解析堆栈数据
const lines = stackString.trim().split('\\n');
console.log("lines----->",lines);
const parsedStack = [];
console.log('\n堆栈调用信息:');
console.log('='.repeat(100));
lines.forEach((line, index) => {
if (line.trim()) {
const parts = line.split(',');
if (parts.length >= 4) {
const level = parseInt(parts[0]);
const methodId = parseInt(parts[1]);
const callCount = parseInt(parts[2]);
const duration = parseInt(parts[3]);
const methodInfo = mapping[methodId];
const methodName = methodInfo ? methodInfo.full : `Unknown_${methodId}`;
// 简单的层级缩进
const indent = '│ '.repeat(level) + (level > 0 ? '├─ ' : '');
// 简洁的单行显示
console.log(`${indent}${methodName} (${duration}ms)`);
parsedStack.push({
level,
methodId,
methodName,
fullSignature: methodInfo ? methodInfo.full : `Method_${methodId}`,
callCount,
duration
});
}
}
});
// 统计信息
const totalDuration = parsedStack.reduce((sum, item) => sum + item.duration, 0);
const maxLevel = Math.max(...parsedStack.map(item => item.level));
const totalCalls = parsedStack.reduce((sum, item) => sum + item.callCount, 0);
console.log('='.repeat(100));
// 按层级统计
const levelStats = {};
parsedStack.forEach(item => {
if (!levelStats[item.level]) {
levelStats[item.level] = { count: 0, totalDuration: 0, totalCalls: 0 };
}
levelStats[item.level].count++;
levelStats[item.level].totalDuration += item.duration;
levelStats[item.level].totalCalls += item.callCount;
});
// 耗时最长的方法
const sortedByDuration = [...parsedStack].sort((a, b) => b.duration - a.duration);
console.log('\n🔥 耗时最长的前10个方法:');
sortedByDuration.slice(0, 10).forEach((item, index) => {
console.log(` ${index + 1}. ${item.methodName} - ${item.duration}ms (${item.callCount}次调用)`);
});
return parsedStack;
} catch (error) {
console.error('❌ 解析错误:', error.message);
return null;
}
}
// 简化方法签名显示
function simplifyMethodSignature(signature) {
try {
// 提取类名和方法名
const lastSlash = signature.lastIndexOf('/');
const firstDot = signature.indexOf('.', lastSlash);
const firstParen = signature.indexOf('(');
if (lastSlash >= 0 && firstDot > lastSlash && firstParen > firstDot) {
const className = signature.substring(lastSlash + 1, firstDot);
const methodName = signature.substring(firstDot + 1, firstParen);
// 提取参数类型(简化显示)
const paramsPart = signature.substring(firstParen + 1, signature.indexOf(')'));
const simplifiedParams = simplifyParams(paramsPart);
return `${className}.${methodName}(${simplifiedParams})`;
}
return signature;
} catch (e) {
return signature;
}
}
// 简化参数类型显示
function simplifyParams(params) {
if (!params) return '';
const typeMap = {
'Z': 'boolean',
'B': 'byte',
'C': 'char',
'S': 'short',
'I': 'int',
'J': 'long',
'F': 'float',
'D': 'double',
'V': 'void'
};
let result = '';
let i = 0;
while (i < params.length) {
if (params[i] === 'L') {
// 对象类型
const semicolon = params.indexOf(';', i);
if (semicolon > i) {
const className = params.substring(i + 1, semicolon);
const simpleName = className.substring(className.lastIndexOf('/') + 1);
result += simpleName;
i = semicolon + 1;
} else {
i++;
}
} else if (params[i] === '[') {
// 数组类型
result += '[]';
i++;
} else if (typeMap[params[i]]) {
result += typeMap[params[i]];
i++;
} else {
i++;
}
if (i < params.length && result && !result.endsWith('[]')) {
result += ', ';
}
}
return result;
}
// 主函数
function main() {
const args = process.argv.slice(2);
if (args.length < 2) {
console.log('🚀 使用方法: node stack-parser.js <mapping文件路径> <堆栈文件路径或字符串>');
console.log('📝 示例1 (文件): node stack-parser.js mapping.txt stack.txt');
console.log('📝 示例2 (字符串): node stack-parser.js mapping.txt "0,1048574,1,710"');
console.log('📋 Mapping文件格式: methodId,methodSignature');
return;
}
const mappingFile = args[0];
const stackInput = args[1];
console.log(`📁 Mapping文件: ${mappingFile}`);
console.log(`🔍 解析堆栈数据...\n`);
parseStackTrace(mappingFile, stackInput);
}
// 如果直接运行此脚本
if (require.main === module) {
main();
}
// 导出函数供其他模块使用
module.exports = { parseStackTrace };
使用方式
node trace_parser.js ~/code/methodMapping.txt "0,1048574,1,905\n1,258336,1...."
Mapping文件: /Users/heyufei/code/methodMapping.txt
🔍 解析堆栈数据...
成功加载 270940 个方法映射
使用传入的堆栈字符串
lines-----> [
'0,1048574,1,905', '1,258336,1,903',
'2,20604,1,897', '3,22106,1,186',
'4,35700,1,186', '5,21656,1,186',
'6,26128,1,181', '7,81196,1,137',
'8,23665,1,137', '3,24006,1,603',
'4,58165,1,503', '5,22284,1,338',
'6,64326,1,338', '7,60162,1,322',
'8,60154,1,322', '9,35700,1,162',
'10,35723,1,162', '11,35700,1,162',
'12,64378,1,162', '13,63526,1,121',
'14,65534,1,110', '15,81196,1,110',
'16,63398,1,110', '17,35700,1,99',
'18,35723,1,99', '19,35700,1,99',
'20,64365,1,99', '21,17766,1,84',
'9,63491,1,160', '10,63497,1,160',
''
]
堆栈调用信息:
====================================================================================================
message_dispatch_start (905ms)
│ ├─ com.lagos.emobility.driver.ui.underway.OrderUnderwayActivity$4.run()V (903ms)
│ │ ├─ com.google.android.libraries.navigation.NavigationView.onCreate(Landroid.os.Bundle;)V (897ms)
│ │ │ ├─ com.google.android.libraries.navigation.environment.l.bl()Lcom.google.android.libraries.navigation.internal.aal.n; (186ms)
│ │ │ │ ├─ com.google.android.libraries.navigation.internal.aes.e.a()Ljava.lang.Object; (186ms)
│ │ │ │ │ ├─ com.google.android.libraries.navigation.environment.ay.a()Ljava.lang.Object; (186ms)
│ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.aal.n.c(Landroid.content.Context;Lcom.google.android.libraries.navigation.internal.aal.ih;Lcom.google.android.libraries.navigation.internal.aal.gf;Lcom.google.android.libraries.navigation.internal.aal.j;Lcom.google.android.libraries.navigation.internal.vi.e;)Lcom.google.android.libraries.navigation.internal.aal.n; (181ms)
│ │ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.yg.bv.a()Ljava.lang.Object; (137ms)
│ │ │ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.aal.ay.a()Ljava.lang.Object; (137ms)
│ │ │ ├─ com.google.android.libraries.navigation.internal.aal.co.aB(Lcom.google.android.gms.maps.GoogleMapOptions;ZLcom.google.android.libraries.navigation.internal.aal.bf;Lcom.google.android.libraries.navigation.internal.aal.n;Lcom.google.android.libraries.navigation.internal.aal.cp;Lcom.google.android.libraries.navigation.internal.aal.gf;)Lcom.google.android.libraries.navigation.internal.aal.co; (603ms)
│ │ │ │ ├─ com.google.android.libraries.navigation.internal.lv.ct.a(Ljava.lang.String;Lcom.google.android.libraries.navigation.internal.aal.bf;Lcom.google.android.libraries.navigation.internal.aal.n;Ljava.lang.String;Ljava.lang.Integer;ILandroid.view.View;Lcom.google.android.libraries.navigation.internal.aal.ab;ZLandroid.widget.TextView;Lcom.google.android.libraries.navigation.internal.aal.ec;Lcom.google.android.libraries.navigation.internal.aal.cb;Lcom.google.android.libraries.navigation.internal.aal.hy;ZLcom.google.android.libraries.navigation.internal.aal.d;Lcom.google.android.libraries.navigation.internal.aal.ag;ZLcom.google.android.libraries.navigation.internal.aal.da;Lcom.google.android.libraries.navigation.internal.aal.bo;)Lcom.google.android.libraries.navigation.internal.aal.ed; (503ms)
│ │ │ │ │ ├─ com.google.android.libraries.navigation.environment.u.run()V (338ms)
│ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.ph.c.h()V (338ms)
│ │ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.nt.h.h()V (322ms)
│ │ │ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.nt.h.b()Lcom.google.android.libraries.navigation.internal.nt.d; (322ms)
│ │ │ │ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.aes.e.a()Ljava.lang.Object; (162ms)
│ │ │ │ │ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.aes.m.a()Ljava.lang.Object; (162ms)
│ │ │ │ │ │ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.aes.e.a()Ljava.lang.Object; (162ms)
│ │ │ │ │ │ │ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.ph.q.a()Ljava.lang.Object; (162ms)
│ │ │ │ │ │ │ │ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.pb.gi.<init>(Ljava.lang.String;Ljava.lang.Integer;Landroid.content.res.Resources;Lcom.google.android.libraries.navigation.internal.px.x;Lcom.google.android.libraries.navigation.internal.nu.m;Landroid.content.Context;Lcom.google.android.libraries.navigation.internal.pf.y;Lcom.google.android.libraries.navigation.internal.acm.an;Lcom.google.android.libraries.navigation.internal.aep.a;Lcom.google.android.libraries.navigation.internal.pb.gn;Lcom.google.android.libraries.navigation.internal.aep.a;Lcom.google.android.libraries.navigation.internal.aep.a;Lcom.google.android.libraries.navigation.internal.pq.k;Landroid.content.Context;Lcom.google.android.libraries.navigation.internal.gb.f;Lcom.google.android.libraries.navigation.internal.kh.b;Lcom.google.android.libraries.navigation.internal.oa.p;Lcom.google.android.libraries.navigation.internal.oz.c;Lcom.google.android.libraries.navigation.internal.mg.b;Lcom.google.android.libraries.navigation.internal.gn.p;Lcom.google.android.libraries.navigation.internal.nd.a;Lcom.google.android.libraries.navigation.internal.ov.s;Lcom.google.android.libraries.navigation.internal.ja.e;Lcom.google.android.libraries.navigation.internal.kc.c;Lcom.google.android.libraries.navigation.internal.ps.d;Lcom.google.android.libraries.navigation.internal.hr.f;Lcom.google.android.libraries.navigation.internal.do.c;Lcom.google.android.libraries.navigation.internal.qm.h;Lcom.google.android.libraries.navigation.internal.oz.a;Lcom.google.android.libraries.navigation.internal.qo.a;Lcom.google.android.libraries.navigation.internal.hu.v;Lcom.google.android.libraries.navigation.internal.zk.bl;Lcom.google.android.libraries.navigation.internal.zk.bl;Ljava.util.concurrent.Executor;Ljava.util.concurrent.Executor;Lcom.google.android.libraries.navigation.internal.zk.bl;Lcom.google.android.libraries.navigation.internal.qi.ce;Lcom.google.android.libraries.navigation.internal.ot.e;Lcom.google.android.libraries.navigation.internal.px.cm;Lcom.google.android.libraries.navigation.internal.pa.g;Lcom.google.android.libraries.navigation.internal.yg.bs;Lcom.google.android.libraries.navigation.internal.nu.r;Lcom.google.android.libraries.navigation.internal.qg.a;Lcom.google.android.libraries.navigation.internal.qq.c;Lcom.google.android.libraries.geo.mapcore.api.model.ba;Z)V (121ms)
│ │ │ │ │ │ │ │ │ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.pk.cv.<init>(Lcom.google.android.libraries.navigation.internal.zk.bl;Lcom.google.android.libraries.navigation.internal.yg.bs;)V (110ms)
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.yg.bv.a()Ljava.lang.Object; (110ms)
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.pb.fw.a()Ljava.lang.Object; (110ms)
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.aes.e.a()Ljava.lang.Object; (99ms)
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.aes.m.a()Ljava.lang.Object; (99ms)
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.aes.e.a()Ljava.lang.Object; (99ms)
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.ph.m.a()Ljava.lang.Object; (99ms)
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├─ com.google.android.libraries.geo.mapcore.renderer.ax.<init>(Landroid.content.Context;Lcom.google.android.libraries.navigation.internal.kh.b;Lcom.google.android.libraries.navigation.internal.nd.a;Lcom.google.android.libraries.navigation.internal.afp.a;Landroid.content.res.Resources;)V (84ms)
│ │ │ │ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.pb.gi.a()Lcom.google.android.libraries.navigation.internal.nt.d; (160ms)
│ │ │ │ │ │ │ │ │ │ ├─ com.google.android.libraries.navigation.internal.pb.gi.i()Lcom.google.android.libraries.navigation.internal.nt.d; (160ms)
====================================================================================================
🔥 耗时最长的前10个方法:
1. message_dispatch_start - 905ms (1次调用)
2. com.lagos.emobility.driver.ui.underway.OrderUnderwayActivity$4.run()V - 903ms (1次调用)
3. com.google.android.libraries.navigation.NavigationView.onCreate(Landroid.os.Bundle;)V - 897ms (1次调用)
4. com.google.android.libraries.navigation.internal.aal.co.aB(Lcom.google.android.gms.maps.GoogleMapOptions;ZLcom.google.android.libraries.navigation.internal.aal.bf;Lcom.google.android.libraries.navigation.internal.aal.n;Lcom.google.android.libraries.navigation.internal.aal.cp;Lcom.google.android.libraries.navigation.internal.aal.gf;)Lcom.google.android.libraries.navigation.internal.aal.co; - 603ms (1次调用)
5. com.google.android.libraries.navigation.internal.lv.ct.a(Ljava.lang.String;Lcom.google.android.libraries.navigation.internal.aal.bf;Lcom.google.android.libraries.navigation.internal.aal.n;Ljava.lang.String;Ljava.lang.Integer;ILandroid.view.View;Lcom.google.android.libraries.navigation.internal.aal.ab;ZLandroid.widget.TextView;Lcom.google.android.libraries.navigation.internal.aal.ec;Lcom.google.android.libraries.navigation.internal.aal.cb;Lcom.google.android.libraries.navigation.internal.aal.hy;ZLcom.google.android.libraries.navigation.internal.aal.d;Lcom.google.android.libraries.navigation.internal.aal.ag;ZLcom.google.android.libraries.navigation.internal.aal.da;Lcom.google.android.libraries.navigation.internal.aal.bo;)Lcom.google.android.libraries.navigation.internal.aal.ed; - 503ms (1次调用)
6. com.google.android.libraries.navigation.environment.u.run()V - 338ms (1次调用)
7. com.google.android.libraries.navigation.internal.ph.c.h()V - 338ms (1次调用)
8. com.google.android.libraries.navigation.internal.nt.h.h()V - 322ms (1次调用)
9. com.google.android.libraries.navigation.internal.nt.h.b()Lcom.google.android.libraries.navigation.internal.nt.d; - 322ms (1次调用)
10. com.google.android.libraries.navigation.environment.l.bl()Lcom.google.android.libraries.navigation.internal.aal.n; - 186ms (1次调用)
7. 问题排查指南
7.1 常见编译错误
错误 1:ASM 版本冲突
java.lang.NoSuchMethodError: org.objectweb.asm.ClassVisitor.<init>
解决方案:
configurations.all {
resolutionStrategy {
force 'org.ow2.asm:asm:9.6'
force 'org.ow2.asm:asm-commons:9.6'
}
}
错误 2:方法映射文件未生成
检查任务依赖关系是否正确配置
解决方案:
// 确保 saveMapping 任务在正确的时机执行
project.tasks.matching { task ->
task.name.contains("transform")
}.configureEach { transformTask ->
transformTask.finalizedBy(mappingTask)
}
7.2 运行时问题
问题1:方法找不到
java.lang.NoSuchMethodError: MethodBeat.i(I)V
解决方案:
# proguard-rules.pro
-keep class com.tencent.matrix.trace.core.MethodBeat {
public static *** i(int);
public static *** o(int);
}
问题2:插桩无效,未启动trace ,trace task 空
tag[Trace_EvilMethod]type[0];key[null];content[{"machine":"HIGH","cpu_app":0,"mem":8055660544,"mem_free":3377132,"detail":"NORMAL","cost":1740,"scene":"com.lagos.emobility.driver.ui.underway.OrderUnderwayActivity","stack":"","stackKey":"","tag":"Trace_EvilMethod","process":"com.lagos.emobility.driver","time":1750319930441}]
解决方案
private TracePlugin configTracePlugin(DynamicConfigImplDemo dynamicConfig) {
//1. 配置设置TracePlugin
TraceConfig config = new TraceConfig.Builder()
.dynamicConfig(dynamicConfig)
.enableAnrTrace(true)
.enableAppMethodBeat(dynamicConfig.isTraceEnable())
.enableEvilMethodTrace(dynamicConfig.isTraceEnable())
.enableTouchEventTrace(true)
.build();
//fix matrix sdk 版本限制
//2. 手动调用 UIThreadMonitor.getMonitor().init(config);
if (!UIThreadMonitor.getMonitor().isInit()) {
try {
UIThreadMonitor.getMonitor().init(config);
} catch (java.lang.RuntimeException e) {
MatrixLog.e(TAG, "[start] RuntimeException:%s", e);
}
}
return new TracePlugin(config);
}
分析
UIThreadMonitor.getMonitor().init(traceConfig);
->> LooperMonitor.registe(xxxx)
->dispatchStart()
-->插桩AppMethodBeat.i(AppMethodBeat.METHOD_ID_DISPATCH);
...
EvilMethodTracer.AnalyseTask.analyse()
-->check AppMethodBeat.METHOD_ID_DISPATCH
慢方法检测 入口必须是这个接入点(消息分发起始点)
8. 总结与展望
8.1 适配成果
- 完全兼容 AGP8:成功迁移到新的 Instrumentation API
- 功能保持完整:所有原有监控功能正常工作
- 解析堆栈:可以正常解析采集到的堆栈数据,用于后续分析
8.2 技术收获
- 深入理解 AGP8 新架构和 API 设计
- 掌握 ASM 字节码操作的最佳实践
- 学会 Gradle 插件开发的现代化模式
8.3 后续优化方向
- 智能采样策略:根据设备性能动态调整采样率
- 增量插桩优化:进一步利用 AGP8 的增量构建能力
- 多模块支持:扩展到 Android Library 项目
- 云端分析集成:与监控后台深度集成
通过这次 TraceCanary 适配 AGP8 的实践,我们不仅解决了兼容性问题,还获得了显著的性能提升。这为后续的 Matrix 其他模块适配提供了宝贵的经验和技术基础。