提交 7dc64461 编写于 作者: N neighbWang 提交者: Johnson Lee

ActivityThread optimization

上级 285a6d34
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
dependencies {
compileOnly project(':booster-android-api')
compile project(':booster-android-instrument')
}
package com.didiglobal.booster.instrument;
import android.os.Handler;
import android.util.Log;
import com.didiglobal.booster.android.bugfix.CaughtCallback;
import static com.didiglobal.booster.android.bugfix.Constants.TAG;
import static com.didiglobal.booster.android.bugfix.Reflection.getFieldValue;
import static com.didiglobal.booster.android.bugfix.Reflection.getStaticFieldValue;
import static com.didiglobal.booster.android.bugfix.Reflection.invokeMethod;
import static com.didiglobal.booster.android.bugfix.Reflection.setFieldValue;
/**
* @author neighbWang
*/
public class ActivityThreadHooker {
private volatile static boolean hooked;
public static void hook() {
if (hooked) {
return;
}
Object thread = null;
try {
thread = android.app.ActivityThread.currentActivityThread();
} catch (final Throwable t1) {
Log.w(TAG, "ActivityThread.currentActivityThread() is inaccessible", t1);
try {
thread = getStaticFieldValue(android.app.ActivityThread.class, "sCurrentActivityThread");
} catch (final Throwable t2) {
Log.w(TAG, "ActivityThread.sCurrentActivityThread is inaccessible", t1);
}
}
if (null == thread) {
Log.w(TAG, "ActivityThread instance is inaccessible");
return;
}
try {
final Handler handler = getHandler(thread);
if (null == handler || !(hooked = setFieldValue(handler, "mCallback", new CaughtCallback(handler)))) {
Log.i(TAG, "Hook ActivityThread.mH.mCallback failed");
}
} catch (final Throwable t) {
Log.w(TAG, "Hook ActivityThread.mH.mCallback failed", t);
}
if(hooked) {
Log.i(TAG, "Hook ActivityThread.mH.mCallback success!");
}
}
private static Handler getHandler(final Object thread) {
Handler handler;
if (null != (handler = getFieldValue(thread, "mH"))) {
return handler;
}
if (null != (handler = invokeMethod(thread, "getHandler"))) {
return handler;
}
try {
if (null != (handler = getFieldValue(thread, Class.forName("android.app.ActivityThread$H")))) {
return handler;
}
} catch (final ClassNotFoundException e) {
Log.w(TAG, "Main thread handler is inaccessible", e);
}
return null;
}
}
apply from: '../gradle/booster.gradle'
dependencies {
kapt "com.google.auto.service:auto-service:1.0-rc4"
implementation project(':booster-android-gradle-api')
implementation project(':booster-task-spi')
implementation project(':booster-transform-asm')
compileOnly 'com.android.tools.build:gradle:3.0.0'
}
package com.didiglobal.booster.transform.activitythread
import com.didiglobal.booster.kotlinx.file
import com.didiglobal.booster.kotlinx.touch
import com.didiglobal.booster.transform.ArtifactManager
import com.didiglobal.booster.transform.TransformContext
import com.didiglobal.booster.transform.activity.thread.Build
import com.didiglobal.booster.transform.asm.ClassTransformer
import com.didiglobal.booster.transform.asm.className
import com.didiglobal.booster.transform.asm.findAll
import com.didiglobal.booster.util.ComponentHandler
import com.google.auto.service.AutoService
import org.objectweb.asm.Opcodes
import org.objectweb.asm.Opcodes.ACC_PUBLIC
import org.objectweb.asm.Opcodes.ALOAD
import org.objectweb.asm.Opcodes.ATHROW
import org.objectweb.asm.Opcodes.INVOKESPECIAL
import org.objectweb.asm.Opcodes.INVOKESTATIC
import org.objectweb.asm.Opcodes.RETURN
import org.objectweb.asm.tree.ClassNode
import org.objectweb.asm.tree.InsnList
import org.objectweb.asm.tree.InsnNode
import org.objectweb.asm.tree.MethodInsnNode
import org.objectweb.asm.tree.MethodNode
import org.objectweb.asm.tree.VarInsnNode
import java.io.PrintWriter
import javax.xml.parsers.SAXParserFactory
/**
* @author neighbWang
*/
@AutoService(ClassTransformer::class)
class ActivityThreadTransformer : ClassTransformer {
private lateinit var logger: PrintWriter
private val applications = mutableSetOf<String>()
override fun onPreTransform(context: TransformContext) {
val parser = SAXParserFactory.newInstance().newSAXParser()
context.artifacts.get(ArtifactManager.MERGED_MANIFESTS).forEach { manifest ->
val handler = ComponentHandler()
parser.parse(manifest, handler)
applications.addAll(handler.applications)
}
this.logger = context.reportsDir.file(Build.ARTIFACT).file(context.name).file("report.txt").touch().printWriter()
}
override fun onPostTransform(context: TransformContext) {
this.logger.close()
}
override fun transform(context: TransformContext, klass: ClassNode): ClassNode {
if (!this.applications.contains(klass.className)) {
return klass
}
val clinit = klass.methods?.find {
"${it.name}${it.desc}" == "<clinit>()V"
} ?: klass.defaultClinit
clinit.instructions?.findAll(RETURN, ATHROW)?.forEach {
clinit.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}.${clinit.name}${clinit.desc}")
}
val init = klass.methods?.find {
"${it.name}${it.desc}" == "<init>()V"
} ?: klass.defaultInit
init.instructions?.findAll(RETURN, ATHROW)?.forEach {
init.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}.${init.name}${init.desc}")
}
val onCreate = klass.methods?.find {
"${it.name}${it.desc}" == "onCreate()V"
} ?: klass.defaultOnCreate
onCreate.instructions?.findAll(RETURN, ATHROW)?.forEach {
onCreate.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}.${onCreate.name}${onCreate.desc}")
}
return klass
}
}
private val ClassNode.defaultClinit: MethodNode
get() = MethodNode(Opcodes.ACC_STATIC, "<clinit>", "()V", null, null).apply {
maxStack = 1
instructions.insert(InsnNode(RETURN))
methods?.add(this)
}
private val ClassNode.defaultInit: MethodNode
get() = MethodNode(ACC_PUBLIC, "<init>", "()V", null, null).apply {
maxStack = 1
instructions.insert(InsnList().apply {
add(VarInsnNode(ALOAD, 0))
add(MethodInsnNode(INVOKESPECIAL, superName, name, desc, false))
add(InsnNode(RETURN))
})
methods?.add(this)
}
private val ClassNode.defaultOnCreate: MethodNode
get() = MethodNode(ACC_PUBLIC, "onCreate", "()V", null, null).apply {
instructions?.add(InsnList().apply {
add(VarInsnNode(ALOAD, 0))
add(MethodInsnNode(INVOKESPECIAL, superName, name, desc, false))
add(InsnNode(RETURN))
})
maxStack = 1
methods?.add(this)
}
const val ACTIVITY_THREAD_HOOKER = "com/didiglobal/booster/instrument/ActivityThreadHooker"
\ No newline at end of file
package com.didiglobal.booster.transform.activitythread
import com.android.build.gradle.api.BaseVariant
import com.android.build.gradle.api.LibraryVariant
import com.didiglobal.booster.gradle.scope
import com.didiglobal.booster.task.spi.VariantProcessor
import com.didiglobal.booster.transform.activity.thread.Build
import com.google.auto.service.AutoService
/**
* @author neighbWang
*/
@AutoService(VariantProcessor::class)
class ActivityThreadVarinatProcessor:VariantProcessor {
override fun process(variant: BaseVariant) {
if (variant !is LibraryVariant) {
variant.scope.globalScope.project.dependencies.add("implementation", "${Build.GROUP}:booster-android-instrument-activity-thread:${Build.VERSION}")
}
}
}
\ No newline at end of file
dependencies {
compile project(':booster-transform-lint')
compile project(':booster-transform-logcat')
compile project(':booster-transform-activity-thread')
compile project(':booster-transform-finalizer-watchdog-daemon')
compile project(':booster-transform-media-player')
compile project(':booster-transform-res-check')
......
include ':booster-aapt2'
include ':booster-android-api'
include ':booster-android-instrument'
include ':booster-android-instrument-activity-thread'
include ':booster-android-instrument-finalizer-watchdog-daemon'
include ':booster-android-instrument-logcat'
include ':booster-android-instrument-media-player'
......@@ -20,6 +21,7 @@ include ':booster-task-compression'
include ':booster-task-dependency'
include ':booster-task-permission'
include ':booster-task-spi'
include ':booster-transform-activity-thread'
include ':booster-transform-all'
include ':booster-transform-asm'
include ':booster-transform-finalizer-watchdog-daemon'
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册