[Matrix系列-4]: TracePlugin 之 EvilMethodTracer 源码分析

本文详细分析了Matrix框架中的TracePlugin组件EvilMethodTracer,探讨了其在编译期如何通过插桩技术记录方法耗时,以及在运行时如何监测卡顿并获取堆栈信息。内容涵盖了构造方法、触发时机、回调逻辑处理,特别是对CPU占用率和堆栈格式的讨论。最后,总结了EvilMethodTracer在性能监控中的作用,并推荐了Android开发者进阶学习资料。
摘要由CSDN通过智能技术生成

背景

evil字面意思是邪恶的、有害的意思。这个方法很邪恶就是该方法存在耗时多的情况,糟老头子坏的很呐!!因此,matrix的目的就是想去统计每个方法的执行耗时。

大体的流程是这样的:在calss字节码转dex文件阶段,通过自定义transform插件,利用ASM工具来操作修改.class文件。在每个方法执行前后插入AppMethodBeat.iAppMethodBeat.o方法,在运行期计算两个的差值就得到方法的耗时。

优点:

  • 兼容性好 无需通过hook手段
  • 优化插桩性能 在方法收集阶段会主动过滤简单的set/get方法,以及一些匿名的构造函数

缺点:

  • 无法统计到系统内执行的函数,但一般卡顿都是由我们自己的App代码导致,所以影响不大

我们先来看下编译期的基本实现(实现细节后续再单独分析):

private class TraceMethodAdapter extends AdviceAdapter {

    private final String methodName;
    private final String name;
    private final String className;
    private final boolean hasWindowFocusMethod;
    private final boolean isNeedTrace;
    private final boolean isActivityOrSubClass;

    // ...省略

    @Override
    protected void onMethodEnter() {
        //注意:并不是所有的方法都执行插桩,只有是我们需要收集的方法才会走插桩逻辑,优化插桩性能!
        TraceMethod traceMethod = collectedMethodMap.get(methodName);
        if (traceMethod != null) {
            traceMethodCount.incrementAndGet();
            mv.visitLdcInsn(traceMethod.id);
            //1, 插入 AppMethodBeat.i 方法
            mv.visitMethodInsn(INVOKESTATIC, TraceBuildConstants.MATRIX_TRACE_CLASS, "i", "(I)V", false);

            if (checkNeedTraceWindowFocusChangeMethod(traceMethod)) {
                // 2, 插入AppMethodBeat.at方法
                traceWindowFocusChangeMethod(mv, className);
            }
        }
    }
       @Override
    protected void onMethodExit(int opcode) {
        TraceMethod traceMethod = collectedMethodMap.get(methodName);
        if (traceMethod != null) {
            traceMethodCount.incrementAndGet();
            mv.visitLdcInsn(traceMethod.id);
            //3, 插入 AppMethodBeat.o 方法
            mv.visitMethodInsn(INVOKESTATIC, TraceBuildConstants.MATRIX_TRACE_CLASS, "o", "(I)V", false);
        }
    }
  //...省略
} 

traceWindowFocusChangeMethod():

private void traceWindowFocusChangeMethod(MethodVisitor mv, String classname) {
    mv.visitVarInsn(Opcodes.ALOAD, 0);
    mv.visitVarInsn(Opcodes.ILOAD, 1);
    mv.visitMethodInsn(Opcodes.INVOKESTATIC, TraceBuildConstants.MATRIX_TRACE_CLASS, "at", "(Landroid/app/Activity;Z)V", false);
} 
  • 总结

编译期插桩主要做了三件事(图片来自官方):

image.png

  1. onMethodEnter()中插入AppMethodBeat.i方法
  2. 收集所有的Activity及其子类,在onWindowFocusChange方法中插入AppMethodBeat.at方法
  3. onMethodExit() 插入 AppMethodBeat.o 方法
  4. 注意:并不是所有的方法都执行插桩,只有属于我们需要收集的方法才会走插桩逻辑,优化插桩性能!

onMethodEnter() App所有方法的进入都会回调; onMethodExit App所有方法的退出都会回调

OK,编译插桩的基本原理已经清楚,现在我们回到EvilMethodTracer类的分析。

一、构造方法

public EvilMethodTracer(TraceConfig config) {
    this.config = config;
    // evil阈值 默认是700ms,外部可以设置
    this.evilThresholdMs = config.getEvilThresholdMs();
    //evil 开关
    this.isEvilMethodTraceEnable = config.isEvilMethodTraceEnable();
} 

简单,配置了两个变量值: evil阈值evil开关

二、触发时机 onAlive

在第三篇文章分析中我们知道,TracePluginstart()方法会调用traceonStartTrace方法。

@Override
public void start() {

//省略...

if (traceConfig.isEvilMethodTraceEnable()) {
    evilMethodTracer.o
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值