ASM插桩基础学习(Kotlin)

617 阅读1分钟

详情可见(顺便求个Star🌟):github.com/stewForAni/…

编译环境

  • Android Studio Flamingo | 2022.2.1 Patch 1
  • GV7.5 / AGP7.4.2
  • Java11

常见功能

  • 日志埋点
  • 性能监控
  • 登录校验

Tips

TransformApi在Gradle7.0废弃,这里采用新Api(参考上述项目)

  • AppExtension替换为AndroidComponentsExtension
  • AsmClassVisitorFactory类可以避免老版Transform中繁琐的io操作
  • MethodVisitor需继承AdviceAdapter,涉及到LocalVariablesSorter类可以对局部变量进行重新排序

使用步骤

  1. 创建library类型的module,除build.gradle和main/java文件夹,其余都删除
  2. 自定义包名,新建xxxplugin文件
class AppPlugin :Plugin<Project>{
    override fun apply(p0: Project) {
        println(" **** AppPlugin start : "+p0.name+" **** ")
        val ex = p0.extensions.getByType(AndroidComponentsExtension::class.java)
        ex.onVariants {
            it.instrumentation.transformClassesWith(MTTransform::class.java,InstrumentationScope.PROJECT) {}
            it.instrumentation.setAsmFramesComputationMode(FramesComputationMode.COMPUTE_FRAMES_FOR_INSTRUMENTED_METHODS)
        }
    }
}
  1. 自定义一个AsmClassVisitorFactory的子类,重写visit和visitMethod方法
abstract class MTTransform : AsmClassVisitorFactory<InstrumentationParameters.None> {
    override fun createClassVisitor(
        classContext: ClassContext,
        nextClassVisitor: ClassVisitor
    ): ClassVisitor {
        return object : ClassVisitor(Opcodes.ASM5, nextClassVisitor) {
            val cName = classContext.currentClassData.className

            override fun visit(
                version: Int,
                access: Int,
                name: String?,
                signature: String?,
                superName: String?,
                interfaces: Array<out String>?
            ) {
                super.visit(version, access, name, signature, superName, interfaces)
                if (classFilter(cName)) {
                    if (classFilter(cName)) {
                        println("---classname = $cName")
                    }
                }
            }

            override fun visitMethod(
                access: Int,
                name: String?,
                descriptor: String?,
                signature: String?,
                exceptions: Array<out String>?
            ): MethodVisitor {
                val mv = super.visitMethod(access, name, descriptor, signature, exceptions)
                if (classFilter(cName)&&methodFilter(name!!)) {
                    println("***method = $name")
                    return MTMethodVisitor(cName, mv, access, name, descriptor)
                }
                return mv
            }
        }
    }

    override fun isInstrumentable(classData: ClassData): Boolean {
        return true
    }

    fun classFilter(cName: String): Boolean {
        return !cName.contains("Base") && (cName.endsWith("Activity") || cName.endsWith("Fragment"))
    }

    fun methodFilter(mName: String): Boolean {
        return !mName.contains("$")&&!mName.contains("<init>")
    }
}
  1. 自定义一个AdviceAdapter的子类xxxMethodVisitor,重写onMethodEnter和onMethodExit
class MTMethodVisitor(
    private val cName: String,
    mv: MethodVisitor,
    access: Int,
    private val mName: String?,
    descriptor: String?
) : AdviceAdapter(Opcodes.ASM5, mv, access, mName, descriptor) {

    override fun onMethodEnter() {
        super.onMethodEnter()
        ...
    }

    override fun onMethodExit(opcode: Int) {
        if (opcode == RETURN) {...}
        super.onMethodExit(opcode)
    }
}
  1. build.gradle配置如下:
plugins {
    id 'org.jetbrains.kotlin.jvm'
    id 'java-gradle-plugin'
    id 'maven-publish'
}

java {
    withJavadocJar()
    withSourcesJar()
}

publishing {
    publications {
        mavenJava(MavenPublication) {
            groupId "io.github.stewforani"
            artifactId "methodtime"
            version "1.0.0"
            from components.java
        }
    }
    repositories {
        maven {
            url "../app_plugin_repo"
        }
    }
}
gradlePlugin {
    plugins {
        MethodTimePlugin {
            id = 'MethodTimePlugin'
            implementationClass = 'com.stew.app_plugin.AppPlugin'
        }
    }
}

dependencies {
    implementation 'com.android.tools.build:gradle:7.4.2'
    implementation 'org.ow2.asm:asm:9.2'
    implementation 'org.ow2.asm:asm-commons:9.2'
}

参考文章: