buildSrc是gradle界定的用来作统一编译的一种配置方式,代码中除了booster-android-instrument方面的代码都适用这个方式来进行统一依赖。 html
booster-gradle-api、booster-gradle-v3_0 booster-gradle-v3_二、booster-gradle-v3_3 是一些扩展类java
booster-gradle-plugin、booster-transform-asm 这里是booster的主要入口,用来进行插庄等操做都须要经过这里来进入android
booster-android-api、booster-android-instrument这些就是提供插庄所须要的类,好比booster-android-instrument-toast对toast进行功能修改,来防止一些系统致使的toast错误api
经过asm的方式替换系统的实现来完成系统bug修复的功能。具体实现以下:bash
val method = klass.methods?.find {
"${it.name}${it.desc}" == "attachBaseContext(Landroid/content/Context;)V"} ?:klass.defaultAttachBaseContext
method.instructions?.findAll(RETURN, ATHROW)?.forEach {
method.instructions?.insertBefore(it, MethodInsnNode(INVOKESTATIC, FINALIZER_WATCHDOG_DAEMON_KILLER, "kill", "()V", false))
logger.println(" + $FINALIZER_WATCHDOG_DAEMON_KILLER.kill()V before @${if (it.opcode == ATHROW) "athrow" else "return"}: ${klass.name}.${method.name}${method.desc} ")
}
复制代码
FinalizerWatchdogDaemonKiller这个的职责就是最多尝试10次,查找java.lang.Daemons$FinalizerWatchdogDaemon这个类,去作反射操做获取他的getinstance,并设置他的thread为空,若是失败就调用stop方法来执行。 可是反射若是上面那个连接所说的,Android 9.0 版本开始限制 Private API 调用,不能再使用反射调用 Daemons 以及 FinalizerWatchdogDaemon 类方法,因此这块应该还能够再优化。app
主要是经过查找如下几种类型对thread的调用来进行代码插庄操做ide
一、 transformInvokeVirtual,检测是调用Thread.start或者Thread.setName,则进行插庄替换实现进行线程的名字替换post
if (context.klassPool.get(THREAD).isAssignableFrom(this.owner)) {
when ("${this.name}${this.desc}") {
"start()V" -> {
method.instructions.insertBefore(this, LdcInsnNode(makeThreadName(klass.className)))
method.instructions.insertBefore(this, MethodInsnNode(Opcodes.INVOKESTATIC, SHADOW_THREAD, "setThreadName", "(Ljava/lang/Thread;Ljava/lang/String;)Ljava/lang/Thread;", false))
logger.println(" + $SHADOW_THREAD.makeThreadName(Ljava/lang/String;Ljava/lang/String;) => ${this.owner}.${this.name}${this.desc}: ${klass.name}.${method.name}${method.desc}")
this.owner = THREAD
}
"setName(Ljava/lang/String;)V" -> {
method.instructions.insertBefore(this, LdcInsnNode(makeThreadName(klass.className)))
method.instructions.insertBefore(this, MethodInsnNode(Opcodes.INVOKESTATIC, SHADOW_THREAD, "makeThreadName", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false))
logger.println(" + $SHADOW_THREAD.makeThreadName(Ljava/lang/String;Ljava/lang/String;) => ${this.owner}.${this.name}${this.desc}: ${klass.name}.${method.name}${method.desc}")
this.owner = THREAD
}
}
}
复制代码
二、transformInvokeSpecial,符合如下一种状况的方法,也进行名字的从新设定gradle
if (this.owner == THREAD && this.name == "<init>") {
when (this.desc) {
"()V",
"(Ljava/lang/Runnable;)V",
"(Ljava/lang/ThreadGroup;Ljava/lang/Runnable;)V" -> {
method.instructions.insertBefore(this, LdcInsnNode(makeThreadName(klass.className)))
val r = this.desc.lastIndexOf(')')
val desc = "${this.desc.substring(0, r)}Ljava/lang/String;${this.desc.substring(r)}"
logger.println(" + $SHADOW_THREAD.makeThreadName(Ljava/lang/String;Ljava/lang/String;) => ${this.owner}.${this.name}${this.desc}: ${klass.name}.${method.name}${method.desc}")
logger.println(" * ${this.owner}.${this.name}${this.desc} => ${this.owner}.${this.name}$desc: ${klass.name}.${method.name}${method.desc}")
this.desc = desc
}
"(Ljava/lang/String;)V",
"(Ljava/lang/ThreadGroup;Ljava/lang/String;)V",
"(Ljava/lang/Runnable;Ljava/lang/String;)V",
"(Ljava/lang/ThreadGroup;Ljava/lang/Runnable;Ljava/lang/String;)V" -> {
method.instructions.insertBefore(this, LdcInsnNode(makeThreadName(klass.className)))
method.instructions.insertBefore(this, MethodInsnNode(Opcodes.INVOKESTATIC, SHADOW_THREAD, "makeThreadName", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false))
logger.println(" + $SHADOW_THREAD.makeThreadName(Ljava/lang/String;Ljava/lang/String;) => ${this.owner}.${this.name}${this.desc}: ${klass.name}.${method.name}${method.desc}")
}
"(Ljava/lang/ThreadGroup;Ljava/lang/Runnable;Ljava/lang/String;J)V" -> {
method.instructions.insertBefore(this, InsnNode(Opcodes.POP2)) // discard the last argument: stackSize
method.instructions.insertBefore(this, LdcInsnNode(makeThreadName(klass.className)))
method.instructions.insertBefore(this, MethodInsnNode(Opcodes.INVOKESTATIC, SHADOW_THREAD, "makeThreadName", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false))
logger.println(" + $SHADOW_THREAD.makeThreadName(Ljava/lang/String;Ljava/lang/String;) => ${this.owner}.${this.name}${this.desc}: ${klass.name}.${method.name}${method.desc}")
this.desc = "(Ljava/lang/ThreadGroup;Ljava/lang/Runnable;Ljava/lang/String;)V"
}
}
}
复制代码
三、transformInvokeStatic,若是是经过线程池方式建立的线程,统一替换成ShadowExecutors来建立线程,保证所产生的线程名字等信息可以统一优化
when (this.owner) {
EXECUTORS -> {
when (this.name) {
//往opcode栈push String常量值 "\u200B"+类名
"defaultThreadFactory" -> {
val r = this.desc.lastIndexOf(')')
val desc = "${this.desc.substring(0, r)}Ljava/lang/String;${this.desc.substring(r)}"
logger.println(" * ${this.owner}.${this.name}${this.desc} => $SHADOW_EXECUTORS.${this.name}$desc: ${klass.name}.${method.name}${method.desc}")
this.owner = SHADOW_EXECUTORS
this.desc = desc
method.instructions.insertBefore(this, LdcInsnNode(makeThreadName(klass.className)))
}
"newCachedThreadPool",
"newFixedThreadPool",
"newSingleThreadExecutor",
"newSingleThreadScheduledExecutor",
"newScheduledThreadPool" -> {
val r = this.desc.lastIndexOf(')')
val name = this.name.replace("new", "newOptimized")
val desc = "${this.desc.substring(0, r)}Ljava/lang/String;${this.desc.substring(r)}"
logger.println(" * ${this.owner}.${this.name}${this.desc} => $SHADOW_EXECUTORS.$name$desc: ${klass.name}.${method.name}${method.desc}")
this.owner = SHADOW_EXECUTORS
this.name = name
this.desc = desc
method.instructions.insertBefore(this, LdcInsnNode(makeThreadName(klass.className)))
}
}
}
}
复制代码
override fun transform(context: TransformContext, klass: ClassNode): ClassNode {
if (!this.applications.contains(klass.className)) {
return klass
}
mapOf(
"<clinit>()V" to klass.defaultClinit,
"<init>()V" to klass.defaultInit,
"onCreate()V" to klass.defaultOnCreate
).forEach { (unique, defaultMethod) ->
val method = klass.methods?.find {
"${it.name}${it.desc}" == unique
} ?: defaultMethod.also {
klass.methods.add(it)
}
method.instructions?.findAll(RETURN, ATHROW)?.forEach {
method.instructions?.insertBefore(it, MethodInsnNode(INVOKESTATIC, ACTIVITY_THREAD_HOOKER, "hook", "()V", false))
logger.println(" + $ACTIVITY_THREAD_HOOKER.hook()V before @${if (it.opcode == ATHROW) "athrow" else "return"}: ${klass.name}.${method.name}${method.desc}")
}
}
return klass
}
复制代码
未完待续