分享一个统计方法执行时间的Gradle 插件(技术点:gradle 插件,asm,代码生成)

说明:

1.该项目处在持续开发阶段,但可以在Debug 阶段使用,目前版本1.0.2 逐步完善中…

2.技术上讲不难实现,但是过程有不少坑

3.按照计划该项目分为两部分

Gradle 插件部分:就是该项目
Python 数据可视化部分:还未开始

用途

统计方法运行时间,效果如下

mtp1.png

快速使用

1.在根项目build.gradle文件中添加我的maven仓库地址,并设置插件依赖

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        //1.我的maven 私有库地址
        maven {
            allowInsecureProtocol = true
            url 'http://161.117.195.45:6677/repository/sand_repo/'
        }
        google()
        mavenCentral()
        maven { url 'https://dl.google.com/dl/android/maven2/' }
        maven { url 'https://www.jitpack.io' }
        jcenter()
        maven { url 'https://jcenter.bintray.com' }

    }
    dependencies {
        classpath "com.android.tools.build:gradle:7.0.4"
        classpath "com.sand.group:mt:1.0.2" //2.依赖插件
    }
}

2.在app的build.gradle 中应用插件,并配置插件参数(MTConfig)

plugins {
    id 'com.android.application'
    id 'com.sand.mt'//应用插件
}

//MTConfig 配置的参数,供插件调用
MTConfig {
    //配置自动生成MTCallBack类锁在的包路径
    mtCallBackPackage="com.mt.autogen.callback"
    //配置哪些包下面的类需要被插桩(这些包下面的方法都会被插桩)
    //这样的配置意味着com.sand.apm.mtdemo包下面的类,除去黑名单,excludeClasses,excludeMethods
    //的方法都会被插桩,如果某个类插桩后,运行时出现class not found
    //请把它的类名添加到excludeClasses中
    pkgs = [
            "com.sand.apm.mtdemo"
    ]
    whiteList = []//白名单这里的方法都插桩
    blackList = []//黑名单这里的方法都不插桩
    excludeMethods = [//这些方法都不插桩
                      "<init>", //构造方法不插桩
                      "<clinit>" //静态域的构造器不插桩
    ]
    excludeClasses = [//这里的类都不需要插桩,直接写类文件名
            "BuildConfig.class",
            "Tool.class"
    ]
}

如果某个类插桩后,运行时出现class not found 请把它的类名添加到excludeClasses中

如果某个类插桩后,运行时出现class not found 请把它的类名添加到excludeClasses中

如果某个类插桩后,运行时出现class not found 请把它的类名添加到excludeClasses中
配置好这些参数后执行同步,make,不出意外的话,你将会在src/main/java 下面看到自动生成的代码。(如果一次不成功多试验几次,实在不行欢迎留言)

make 之后插件会在gradle.properties 文件中生成一个mt.work变量,如果你想关闭插件,配置其为false即可

------------------------分割线----------------------------

原理

利用gradle插件在编译后的class文件的方法调用开始和调用结束时候插入统计代码,实际效果如下

插桩前代码:

public static void method1(){
    
    
    System.out.println("我是method1");
}

插桩后反编译代码

public static void method1() {
    
    
    long currentTimeMillis = System.currentTimeMillis();
    System.out.println("我是method1");
    MTCallBack.mtDone(currentTimeMillis);
    }

这里的MTCallBack是一个编译时动态生成的MTCallBack.Java文件,默认生成的代码如下,你可以在这个类里面写任何代码,比如收集App运行时的各种信息


public class MTCallBack{
    
    

   public String tag="mt";
   public static void mtDone(long start) {
    
    

      long end = System.currentTimeMillis();
      long cost = end - start;
      StackTraceElement[] sts = Thread.currentThread().getStackTrace();
      //sts[3] 就是mtDone被调用所在的方法,也可以循环向上查询更深的栈层级
      String currentMethodName = sts[3].getClassName() + "." + sts[3].getMethodName();
      String mtLog = currentMethodName + " 耗时:" + cost + " ms,Thread.name:" +    Thread.currentThread().getName();

      if (cost < 100) {
    
    
         Log.w("mt",mtLog);
      } else {
    
    
         Log.e("mt",mtLog);
      }
   }
}

目前进度,存在的问题,未来计划

目前进度

已经在Windows上测试通过,Mac还没有来得及测试,预计很快完成

存在的问题

暂时只能在debug模式下使用(考虑到性能问题和确保App运行稳定),后期逐步完善

未来计划

我开发这个小插件的目的是替代Android Studio Profiler 火焰图的(因为我觉得火焰图看着不直观,而且有点麻烦,也不能进行多次数据对比),未来预计会朝着这个方向发展(数据更加直观方便,并丰富MTCallBack的默认功能)如果有兴趣参加这个小项目小伙伴欢迎留言 。

源码地址:https://github.com/woshiwzy/APM_MT

猜你喜欢

转载自blog.csdn.net/wang382758656/article/details/124236006