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

Res check when application launched

上级 1be4253b
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.app.Application;
import android.os.Process;
import android.util.Log;
import static com.didiglobal.booster.android.bugfix.Constants.TAG;
/**
* @author neighbWang
*/
public class ResChecker {
public static void checkRes(final Application app) {
if (null == app.getAssets() || null == app.getResources()) {
final int pid = Process.myPid();
Log.w(TAG, "Process " + pid + " is going to be killed");
Process.killProcess(pid);
System.exit(10);
}
}
}
......@@ -7,4 +7,5 @@ dependencies {
compile project(':booster-transform-usage')
compile project(':booster-transform-media-player')
compile project(':booster-transform-webview')
compile project(':booster-transform-res-check')
}
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.res.check
import com.didiglobal.booster.kotlinx.asIterable
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.asm.ClassTransformer
import com.didiglobal.booster.transform.asm.className
import com.didiglobal.booster.util.ComponentHandler
import com.google.auto.service.AutoService
import org.objectweb.asm.Opcodes.ACC_PROTECTED
import org.objectweb.asm.Opcodes.ACC_PUBLIC
import org.objectweb.asm.Opcodes.ALOAD
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 ResCheckTransformer : 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 attachBaseContext = klass.methods?.find {
"${it.name}${it.desc}" == "attachBaseContext(Landroid/content/Context;)V"
} ?: klass.defaultAttachBaseContext
attachBaseContext.instructions?.apply {
iterator().asIterable().find {
it.opcode == INVOKESPECIAL
&& context.klassPool.get(APPLICATION).isAssignableFrom((it as MethodInsnNode).owner)
&& "${it.name}${it.desc}" == "attachBaseContext(Landroid/content/Context;)V"
}?.let {
insert(it, InsnList().apply {
add(VarInsnNode(ALOAD, 0))
add(MethodInsnNode(INVOKESTATIC, RES_CHECKER, "checkRes", "(Landroid/app/Application;)V", false))
})
logger.println(" + $RES_CHECKER.checkRes(Landroid/app/Application;)V after ${(it as MethodInsnNode).owner}.${it.name}${it.desc} : ${klass.name}.${it.name}${it.desc} ")
}
}
val onCreate = klass.methods?.find {
"${it.name}${it.desc}" == "onCreate()V"
} ?: klass.defaultOnCreate
onCreate.instructions?.apply {
iterator().asIterable().find {
it.opcode == INVOKESPECIAL && context.klassPool.get(APPLICATION).isAssignableFrom((it as MethodInsnNode).owner) && "${it.name}${it.desc}" == "onCreate()V"
}.let {
insert(it, InsnList().apply {
add(VarInsnNode(ALOAD, 0))
add(MethodInsnNode(INVOKESTATIC, RES_CHECKER, "checkRes", "(Landroid/app/Application;)V", false))
})
logger.println(" + $RES_CHECKER.checkRes(Landroid/app/Application;)V after ${(it as MethodInsnNode).owner}.${it.name}${it.desc} : ${klass.name}.${it.name}${it.desc} ")
}
}
return klass
}
}
private val ClassNode.defaultAttachBaseContext: MethodNode
get() = MethodNode(ACC_PROTECTED, "attachBaseContext", "(Landroid/content/Context;)V", null, null).apply {
instructions?.add(InsnList().apply {
add(VarInsnNode(ALOAD, 0))
add(VarInsnNode(ALOAD, 1))
add(MethodInsnNode(INVOKESPECIAL, superName, name, desc, false))
add(InsnNode(RETURN))
})
maxStack = 1
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 APPLICATION = "android/app/Application"
const val RES_CHECKER = "com/didiglobal/booster/instrument/ResChecker"
package com.didiglobal.booster.transform.res.check
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.google.auto.service.AutoService
/**
* @author neighbWang
*/
@AutoService(VariantProcessor::class)
class ResCheckVarinatProcessor : VariantProcessor {
override fun process(variant: BaseVariant) {
if (variant !is LibraryVariant) {
variant.scope.globalScope.project.dependencies.add("implementation", "${Build.GROUP}:booster-android-instrument-res-check:${Build.VERSION}")
}
}
}
\ No newline at end of file
......@@ -6,6 +6,7 @@ include ':booster-android-instrument-shared-preferences'
include ':booster-android-instrument-thread'
include ':booster-android-instrument-toast'
include ':booster-android-instrument-webview'
include ':booster-android-instrument-res-check'
include ':booster-android-gradle-api'
include ':booster-android-gradle-v3_0'
include ':booster-android-gradle-v3_2'
......@@ -30,4 +31,5 @@ include ':booster-transform-usage'
include ':booster-transform-util'
include ':booster-kotlinx'
include ':booster-transform-webview'
include ':booster-transform-res-check'
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册