diff --git a/Android/app/build.gradle b/Android/app/build.gradle index f0ec90e4ca22aed88eb5ca1ec42ab47cf7a419d9..489e314bbee50bd1586a1d1535b44c25af52a590 100644 --- a/Android/app/build.gradle +++ b/Android/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-kapt' apply from: 'doraemonkit.gradle' android { @@ -73,7 +74,7 @@ dokitExt { //通用设置 comm { //地图经纬度开关 - gpsSwitch true + gpsSwitch false //网络开关 networkSwitch true //大图开关 @@ -83,14 +84,14 @@ dokitExt { slowMethod { //0:默认模式 打印函数调用栈 需添加指定入口 默认为application onCreate 和attachBaseContext //1:普通模式 运行时打印某个函数的耗时 全局业务代码函数插入 - strategy 1 + strategy 0 //函数功能开关 methodSwitch true //调用栈模式配置 stackMethod { //默认值为 5ms 小于该值的函数在调用栈中不显示 - thresholdTime 10 + thresholdTime 5 //调用栈函数入口 enterMethods = ["com.didichuxing.doraemondemo.MainDebugActivity.test1"] } diff --git a/Android/app/doraemonkit.gradle b/Android/app/doraemonkit.gradle index 35d825958510319145b68b8b7c9fbb824604d8d6..5c26b2ae49b9a82771bc7ab43afd9038f512e7bb 100644 --- a/Android/app/doraemonkit.gradle +++ b/Android/app/doraemonkit.gradle @@ -5,7 +5,7 @@ if (rootProject.ext.config["applyPlugin"]) { dependencies { //外部平台依赖 debugImplementation project(":doraemonkit") - debugImplementation project(":doraemonkit-weex") + //debugImplementation project(":doraemonkit-weex") // releaseImplementation project(":doraemonkit-no-op") // debugImplementation project(":doraemonkit-leakcanary") //新版线上包 diff --git a/Android/app/src/debug/java/com/didichuxing/doraemondemo/App.kt b/Android/app/src/debug/java/com/didichuxing/doraemondemo/App.kt index c0b4fb46009d00041bd4bf288f45b0aea285ede3..3ab74807864864fd9dc1bcff0cd0b2ed913900d8 100644 --- a/Android/app/src/debug/java/com/didichuxing/doraemondemo/App.kt +++ b/Android/app/src/debug/java/com/didichuxing/doraemondemo/App.kt @@ -32,8 +32,8 @@ class App : Application() { // kits.add(DemoKit()) // kits.add(DemoKit()) val mapKits: LinkedHashMap> = linkedMapOf() - mapKits.put("业务专区1", mutableListOf(DemoKit())) - mapKits.put("业务专区2", mutableListOf(DemoKit())) + mapKits["业务专区1"] = mutableListOf(DemoKit()) + mapKits["业务专区2"] = mutableListOf(DemoKit()) DoraemonKit.install(this, mapKits = mapKits, productId = "749a0600b5e48dd77cf8ee680be7b1b7") val config = ImagePipelineConfig.newBuilder(this) diff --git a/Android/app/src/debug/java/com/didichuxing/doraemondemo/MainDebugActivity.kt b/Android/app/src/debug/java/com/didichuxing/doraemondemo/MainDebugActivity.kt index 26c644aadddefa74107dcadcd600a40e7d761573..e66f08e3fab2e962fb2d35c579240bee01b1c1b8 100644 --- a/Android/app/src/debug/java/com/didichuxing/doraemondemo/MainDebugActivity.kt +++ b/Android/app/src/debug/java/com/didichuxing/doraemondemo/MainDebugActivity.kt @@ -25,24 +25,19 @@ import com.baidu.location.BDAbstractLocationListener import com.baidu.location.BDLocation import com.baidu.location.LocationClient import com.baidu.location.LocationClientOption -import com.blankj.utilcode.util.* +import com.blankj.utilcode.util.ConvertUtils +import com.blankj.utilcode.util.ThreadUtils import com.blankj.utilcode.util.ThreadUtils.SimpleTask import com.bumptech.glide.Glide import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.resource.bitmap.CircleCrop import com.didichuxing.doraemondemo.retrofit.GithubService import com.didichuxing.doraemonkit.DoraemonKit -import com.didichuxing.doraemonkit.aop.method_stack.MethodInvokNode -import com.didichuxing.doraemonkit.aop.method_stack.MethodStackBean -import com.didichuxing.doraemonkit.aop.method_stack.MethodStackUtil import com.didichuxing.doraemonkit.okgo.DokitOkGo import com.didichuxing.doraemonkit.okgo.callback.StringCallback import com.didichuxing.doraemonkit.okgo.model.Response import com.facebook.drawee.backends.pipeline.Fresco import com.facebook.drawee.view.SimpleDraweeView -import com.google.gson.Gson -import com.google.gson.GsonBuilder -import com.google.gson.JsonObject import com.nostra13.universalimageloader.core.ImageLoader import com.nostra13.universalimageloader.core.ImageLoaderConfiguration import com.squareup.picasso.MemoryPolicy @@ -54,7 +49,6 @@ import com.tencent.map.geolocation.TencentLocationRequest import io.reactivex.schedulers.Schedulers import kotlinx.android.synthetic.main.activity_main.* import okhttp3.* -import org.json.JSONArray import org.json.JSONObject import pub.devrel.easypermissions.EasyPermissions import pub.devrel.easypermissions.PermissionRequest @@ -62,9 +56,7 @@ import retrofit2.Retrofit import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory import retrofit2.converter.gson.GsonConverterFactory import java.io.* -import java.lang.reflect.Type import java.net.* -import java.util.ArrayList /** * @author jintai @@ -198,10 +190,8 @@ class MainDebugActivity : BaseActivity(), View.OnClickListener { private val mLocationListener: LocationListener = object : LocationListener { override fun onLocationChanged(location: Location) { - if (location != null) { - val string = "lat====>" + location.latitude + " lng====>" + location.longitude - Log.i(TAG, "系统定位====>$string") - } + val string = "lat====>" + location.latitude + " lng====>" + location.longitude + Log.i(TAG, "系统定位====>$string") } override fun onProviderDisabled(arg0: String) {} @@ -440,7 +430,7 @@ class MainDebugActivity : BaseActivity(), View.OnClickListener { .url("http://cdn1.lbesec.com/products/history/20131220/privacyspace_rel_2.2.1617.apk") .build() } - val call = okHttpClient!!.newCall(request) + val call = okHttpClient!!.newCall(request!!) val startTime = SystemClock.uptimeMillis() call.enqueue(object : Callback { override fun onFailure(call: Call, e: IOException) { diff --git a/Android/app/src/main/java/com/didichuxing/doraemondemo/AopTest.java b/Android/app/src/main/java/com/didichuxing/doraemondemo/AopTest.java index a0cc34f5d041d49932d9bad50cf51a58ba12ab59..6ce4d4559f77a53cfe9d540aa3e49feae2da1195 100644 --- a/Android/app/src/main/java/com/didichuxing/doraemondemo/AopTest.java +++ b/Android/app/src/main/java/com/didichuxing/doraemondemo/AopTest.java @@ -3,6 +3,7 @@ package com.didichuxing.doraemondemo; import android.util.Log; import com.didichuxing.doraemonkit.aop.DokitPluginConfig; +import com.didichuxing.doraemonkit.aop.method_stack.MethodStackUtil; import com.didichuxing.doraemonkit.aop.urlconnection.HttpUrlConnectionProxyUtil; import java.io.IOException; @@ -25,14 +26,8 @@ public class AopTest { private static final String TAG = "AopTest"; public void test() { - try { - URL url = new URL("sss"); - URLConnection connection = url.openConnection(); - connection.setReadTimeout(1000); - connection.connect(); - } catch (IOException e) { - e.printStackTrace(); - } + //MethodStackUtil.getInstance().recodeObjectMethodCostStart(10, 5, 0, "AopTest", "test", "desc", this); + MethodStackUtil.getInstance().recodeStaticMethodCostStart(10, 5, 7, "AopTest", "test", "desc"); } diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitExt.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitExt.kt index 2c6afcdc0a84eb1a0a726c90576addf9d253b09b..a30a0517beaf5b9b91d8d4e9f54ba47a1304da40 100644 --- a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitExt.kt +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitExt.kt @@ -1,8 +1,10 @@ package com.didichuxing.doraemonkit.plugin import org.objectweb.asm.Opcodes.* +import org.objectweb.asm.tree.ClassNode import org.objectweb.asm.tree.InsnList import org.objectweb.asm.tree.InsnNode +import org.objectweb.asm.tree.MethodInsnNode /** * ================================================ @@ -14,8 +16,8 @@ import org.objectweb.asm.tree.InsnNode * ================================================ */ -fun InsnList.methodExitInsnNode(): InsnNode? { - return this.iterator()?.asSequence()?.filterIsInstance(InsnNode::class.java)?.find { +fun InsnList.getMethodExitInsnNodes(): Sequence? { + return this.iterator()?.asSequence()?.filterIsInstance(InsnNode::class.java)?.filter { it.opcode == RETURN || it.opcode == IRETURN || it.opcode == FRETURN || @@ -24,4 +26,7 @@ fun InsnList.methodExitInsnNode(): InsnNode? { it.opcode == DRETURN || it.opcode == ATHROW } -} \ No newline at end of file +} + +val MethodInsnNode.ownerClassName: String + get() = owner.replace('/', '.') \ No newline at end of file diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitExtUtil.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitExtUtil.kt index ebac863bac229e96874d98f945f2d14246bf546c..3cfe221fb740a6994f51742eb37f222b7874108d 100644 --- a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitExtUtil.kt +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitExtUtil.kt @@ -3,6 +3,8 @@ package com.didichuxing.doraemonkit.plugin import com.didichuxing.doraemonkit.plugin.extension.CommExt import com.didichuxing.doraemonkit.plugin.extension.DoKitExt import com.didichuxing.doraemonkit.plugin.extension.SlowMethodExt +import com.didichuxing.doraemonkit.plugin.extension.SlowMethodExt.Companion.STRATEGY_NORMAL +import com.didichuxing.doraemonkit.plugin.stack_method.MethodStackNodeUtil /** * ================================================ @@ -21,7 +23,11 @@ object DoKitExtUtil { */ private var mDokitPluginSwitch = true private var mDokitLogSwitch = false - private var mUsefulInRelease = false + + /** + * 默认函数调用为5级 + */ + public var mStackMethodLevel = 5 private val applications: MutableSet = mutableSetOf() var commExt = CommExt() private set @@ -35,11 +41,6 @@ object DoKitExtUtil { return mDokitLogSwitch } - fun usefulInRelease(): Boolean { - return mUsefulInRelease - } - - /** * 初始化 * @@ -49,7 +50,6 @@ object DoKitExtUtil { fun init(dokitEx: DoKitExt, applicationId: String) { mDokitPluginSwitch = dokitEx.dokitPluginSwitch mDokitLogSwitch = dokitEx.dokitLogSwitch - mUsefulInRelease = dokitEx.usefulInRelease //设置普通的配置 commExt = dokitEx.comm slowMethodExt.strategy = dokitEx.slowMethod.strategy @@ -97,8 +97,10 @@ object DoKitExtUtil { /** * ============慢函数stack策略的配置 end========== */ + } + fun setApplications(applications: MutableSet) { if (applications.isEmpty()) { return diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitPlugin.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitPlugin.kt index 089c3c379535c349bccf550f0f2b5d2d4813ffe2..e18c9b17aea0847c77f1c2d13dcd37ef5f58067a 100644 --- a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitPlugin.kt +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitPlugin.kt @@ -3,8 +3,11 @@ package com.didichuxing.doraemonkit.plugin import com.android.build.gradle.AppExtension import com.android.build.gradle.LibraryExtension import com.didichuxing.doraemonkit.plugin.extension.DoKitExt +import com.didichuxing.doraemonkit.plugin.stack_method.MethodStackNodeUtil +import com.didichuxing.doraemonkit.plugin.transform.* import com.didiglobal.booster.annotations.Priority import com.didiglobal.booster.gradle.getAndroid +import com.didiglobal.booster.gradle.getProperty import com.didiglobal.booster.task.spi.VariantProcessor import org.gradle.api.Plugin import org.gradle.api.Project @@ -25,6 +28,13 @@ class DoKitPlugin : Plugin { //创建指定扩展 并将project 传入构造函数 project.extensions.create("dokitExt", DoKitExt::class.java) + +// val debug = project.gradle.startParameter.taskNames.any { +// it.contains("debug") || it.contains("Debug") +// } +// if (!debug) { +// return +// } project.gradle.addListener(DoKitTransformTaskExecutionListener(project)) //println("project.plugins===>${project.plugins}") @@ -68,8 +78,20 @@ class DoKitPlugin : Plugin { when { project.plugins.hasPlugin("com.android.application") || project.plugins.hasPlugin("com.android.dynamic-feature") -> { project.getAndroid().let { androidExt -> + val methodStackLevel = project.getProperty("DoKit_MethodStack_Level", 5) + DoKitExtUtil.mStackMethodLevel = methodStackLevel + MethodStackNodeUtil.METHOD_STACK_KEYS.clear() //注册transform - androidExt.registerTransform(DoKitTransform(project)) + androidExt.registerTransform(DoKitCommTransform(project)) + MethodStackNodeUtil.METHOD_STACK_KEYS.add(0, mutableSetOf()) + val methodStackRange = 1 until methodStackLevel + if (methodStackLevel > 1) { + for (index in methodStackRange) { + MethodStackNodeUtil.METHOD_STACK_KEYS.add(index, mutableSetOf()) + androidExt.registerTransform(DoKitDependTransform(project, index)) + } + } + //项目评估完毕回调 project.afterEvaluate { this.variantProcessors.let { processors -> @@ -85,7 +107,7 @@ class DoKitPlugin : Plugin { project.plugins.hasPlugin("com.android.library") -> { project.getAndroid().let { libraryExt -> - libraryExt.registerTransform(DoKitTransform(project)) + libraryExt.registerTransform(DoKitCommTransform(project)) project.afterEvaluate { this.variantProcessors.let { processors -> libraryExt.libraryVariants.forEach { variant -> diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitTransformInvocation.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitTransformInvocation.kt index b6a594f8b8973063349892355ba5d93a7d147e4b..5851bf8c41aae1e71d4d49f4a005c5348c1a7d3b 100644 --- a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitTransformInvocation.kt +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitTransformInvocation.kt @@ -13,6 +13,7 @@ import com.android.build.api.transform.Status.REMOVED import com.android.build.api.transform.TransformInput import com.android.build.api.transform.TransformInvocation import com.android.build.api.transform.TransformOutputProvider +import com.didichuxing.doraemonkit.plugin.transform.DoKitBaseTransform import com.didiglobal.booster.gradle.* import com.didiglobal.booster.kotlinx.NCPU import com.didiglobal.booster.transform.AbstractKlassPool @@ -30,7 +31,7 @@ import java.util.concurrent.Future * * @author johnsonlee */ -internal class DoKitTransformInvocation(private val delegate: TransformInvocation, internal val transform: DoKitTransform) : TransformInvocation, TransformContext, ArtifactManager { +internal class DoKitTransformInvocation(private val delegate: TransformInvocation, internal val transform: DoKitBaseTransform) : TransformInvocation, TransformContext, ArtifactManager { private val executor = Executors.newWorkStealingPool(NCPU) diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/asmclasstransformer/BaseDoKitClassTransformer.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/asmclasstransformer/BaseDoKitClassTransformer.kt new file mode 100644 index 0000000000000000000000000000000000000000..bf14cd1dab687ad60983aa9cd869035f74476b06 --- /dev/null +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/asmclasstransformer/BaseDoKitClassTransformer.kt @@ -0,0 +1,15 @@ +package com.didichuxing.doraemonkit.plugin.asmclasstransformer + +import com.didiglobal.booster.transform.asm.ClassTransformer + +/** + * ================================================ + * 作 者:jint(金台) + * 版 本:1.0 + * 创建日期:2020/5/21-16:54 + * 描 述: + * 修订历史: + * ================================================ + */ +open class BaseDoKitClassTransformer : ClassTransformer { +} \ No newline at end of file diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/asmclasstransformer/MethodStackDepTransformer.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/asmclasstransformer/MethodStackDepTransformer.kt new file mode 100644 index 0000000000000000000000000000000000000000..b76004308d4894595be304395601b5a22d61b024 --- /dev/null +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/asmclasstransformer/MethodStackDepTransformer.kt @@ -0,0 +1,138 @@ +package com.didichuxing.doraemonkit.plugin.asmclasstransformer + +import com.didichuxing.doraemonkit.plugin.DoKitExtUtil +import com.didichuxing.doraemonkit.plugin.extension.SlowMethodExt +import com.didichuxing.doraemonkit.plugin.getMethodExitInsnNodes +import com.didichuxing.doraemonkit.plugin.ownerClassName +import com.didichuxing.doraemonkit.plugin.stack_method.MethodStackNode +import com.didichuxing.doraemonkit.plugin.stack_method.MethodStackNodeUtil +import com.didiglobal.booster.transform.TransformContext +import com.didiglobal.booster.transform.asm.asIterable +import com.didiglobal.booster.transform.asm.className +import org.objectweb.asm.Opcodes.* +import org.objectweb.asm.tree.* + +/** + * ================================================ + * 作 者:jint(金台) + * 版 本:1.0 + * 创建日期:2020/5/14-18:07 + * 描 述:入口函数 慢函数调用栈 wiki:https://juejin.im/post/5e8d87c4f265da47ad218e6b + * 修订历史:不要指定自动注入 需要手动在DoKitAsmTransformer中通过配置创建 + * 原理:transform()方法的调用是无序的 原因:哪一个class会先被transformer执行是不确定的 但是每一个class被transformer执行顺序是遵循transformer的Priority规则的 + * ================================================ + */ +class MethodStackDepTransformer(private val level: Int = 1) : BaseDoKitClassTransformer() { + + private val thresholdTime = DoKitExtUtil.slowMethodExt.stackMethod.thresholdTime + override fun transform(context: TransformContext, klass: ClassNode): ClassNode { + if (!DoKitExtUtil.dokitPluginSwitchOpen()) { + return klass + } + + if (!DoKitExtUtil.slowMethodExt.methodSwitch) { + return klass + } + + if (DoKitExtUtil.slowMethodExt.strategy == SlowMethodExt.STRATEGY_NORMAL) { + return klass + } + + if (DoKitExtUtil.ignorePackageNames(klass.className)) { + return klass + } + + + val methodStackKeys: MutableSet = MethodStackNodeUtil.METHOD_STACK_KEYS[level - 1] + + klass.methods.forEach { methodNode -> + val key = "${klass.className}&${methodNode.name}&${methodNode.desc}" + if (methodStackKeys.contains(key)) { + println("level===>$level mathched key===>$key") + operateMethodInsn(klass, methodNode) + } + + } + + return klass + } + + + private fun operateMethodInsn(klass: ClassNode, methodNode: MethodNode) { + //读取全是函数调用的指令 + methodNode.instructions.asIterable().filterIsInstance(MethodInsnNode::class.java).filter { methodInsnNode -> + methodInsnNode.name != "" + }.forEach { methodInsnNode -> + val methodStackNode = MethodStackNode(level, methodInsnNode.ownerClassName, methodInsnNode.name, methodInsnNode.desc, klass.className, methodNode.name, methodNode.desc) + MethodStackNodeUtil.addMethodStackNode(level, methodStackNode) + } + //函数出入口插入耗时统计代码 + //方法入口插入 + methodNode.instructions.insert(createMethodEnterInsnList(level, klass.className, methodNode.name, methodNode.desc, methodNode.access)) + //方法出口插入 + methodNode.instructions.getMethodExitInsnNodes()?.forEach { methodExitInsnNode -> + methodNode.instructions.insertBefore(methodExitInsnNode, createMethodExitInsnList(level, klass.className, methodNode.name, methodNode.desc, methodNode.access)) + } + } + + + /** + * 创建慢函数入口指令集 + */ + private fun createMethodEnterInsnList(level: Int, className: String, methodName: String, desc: String, access: Int): InsnList { + val isStaticMethod = access and ACC_STATIC != 0 + val insnList = InsnList() + if (isStaticMethod) { + insnList.add(MethodInsnNode(INVOKESTATIC, "com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil", "getInstance", "()Lcom/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil;", false)) + insnList.add(IntInsnNode(BIPUSH, DoKitExtUtil.mStackMethodLevel)) + insnList.add(IntInsnNode(BIPUSH, thresholdTime)) + insnList.add(IntInsnNode(BIPUSH, level)) + insnList.add(LdcInsnNode(className)) + insnList.add(LdcInsnNode(methodName)) + insnList.add(LdcInsnNode(desc)) + insnList.add(MethodInsnNode(INVOKEVIRTUAL, "com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil", "recodeStaticMethodCostStart", "(IIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", false)) + } else { + insnList.add(MethodInsnNode(INVOKESTATIC, "com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil", "getInstance", "()Lcom/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil;", false)) + insnList.add(IntInsnNode(BIPUSH, DoKitExtUtil.mStackMethodLevel)) + insnList.add(IntInsnNode(BIPUSH, thresholdTime)) + insnList.add(IntInsnNode(BIPUSH, level)) + insnList.add(LdcInsnNode(className)) + insnList.add(LdcInsnNode(methodName)) + insnList.add(LdcInsnNode(desc)) + insnList.add(VarInsnNode(ALOAD, 0)) + insnList.add(MethodInsnNode(INVOKEVIRTUAL, "com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil", "recodeObjectMethodCostStart", "(IIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V", false)) + } + + return insnList + } + + + /** + * 创建慢函数退出时的指令集 + */ + private fun createMethodExitInsnList(level: Int, className: String, methodName: String, desc: String, access: Int): InsnList { + val isStaticMethod = access and ACC_STATIC != 0 + val insnList = InsnList() + if (isStaticMethod) { + insnList.add(MethodInsnNode(INVOKESTATIC, "com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil", "getInstance", "()Lcom/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil;", false)) + insnList.add(IntInsnNode(BIPUSH, thresholdTime)) + insnList.add(IntInsnNode(BIPUSH, level)) + insnList.add(LdcInsnNode(className)) + insnList.add(LdcInsnNode(methodName)) + insnList.add(LdcInsnNode(desc)) + insnList.add(MethodInsnNode(INVOKEVIRTUAL, "com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil", "recodeStaticMethodCostEnd", "(IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", false)) + } else { + insnList.add(MethodInsnNode(INVOKESTATIC, "com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil", "getInstance", "()Lcom/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil;", false)) + insnList.add(IntInsnNode(BIPUSH, thresholdTime)) + insnList.add(IntInsnNode(BIPUSH, level)) + insnList.add(LdcInsnNode(className)) + insnList.add(LdcInsnNode(methodName)) + insnList.add(LdcInsnNode(desc)) + insnList.add(VarInsnNode(ALOAD, 0)) + insnList.add(MethodInsnNode(INVOKEVIRTUAL, "com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil", "recodeObjectMethodCostEnd", "(IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V", false)) + } + return insnList + } + +} + diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/asmtransformer/BaseDoKitAsmTransformer.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/asmtransformer/BaseDoKitAsmTransformer.kt new file mode 100644 index 0000000000000000000000000000000000000000..d2a35c02e35e29f52ec2bce018093de614a91f1d --- /dev/null +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/asmtransformer/BaseDoKitAsmTransformer.kt @@ -0,0 +1,82 @@ +package com.didichuxing.doraemonkit.plugin.asmtransformer + +import com.didichuxing.doraemonkit.plugin.asmclasstransformer.BaseDoKitClassTransformer +import com.didiglobal.booster.annotations.Priority +import com.didiglobal.booster.transform.TransformContext +import com.didiglobal.booster.transform.Transformer +import org.objectweb.asm.ClassReader +import org.objectweb.asm.ClassWriter +import org.objectweb.asm.tree.ClassNode +import java.lang.management.ManagementFactory +import java.lang.management.ThreadMXBean + +/** + * ================================================ + * 作 者:jint(金台) + * 版 本:1.0 + * 创建日期:2020/5/21-16:44 + * 描 述: + * 修订历史: + * ================================================ + */ +open class BaseDoKitAsmTransformer : Transformer { + private val threadMxBean = ManagementFactory.getThreadMXBean() + + private val durations = mutableMapOf() + + internal val transformers: Collection + + /** + * For unit test only + */ + constructor(vararg transformers: BaseDoKitClassTransformer) { + this.transformers = transformers.sortedBy { + it.javaClass.getAnnotation(Priority::class.java)?.value ?: 0 + } + } + + override fun onPreTransform(context: TransformContext) { + this.transformers.forEach { transformer -> + this.threadMxBean.sumCpuTime(transformer) { + transformer.onPreTransform(context) + } + } + } + + override fun transform(context: TransformContext, bytecode: ByteArray): ByteArray { + return ClassWriter(ClassWriter.COMPUTE_MAXS).also { writer -> + this.transformers.fold(ClassNode().also { klass -> + ClassReader(bytecode).accept(klass, 0) + }) { klass, transformer -> + this.threadMxBean.sumCpuTime(transformer) { + transformer.transform(context, klass) + } + }.accept(writer) + }.toByteArray() + } + + override fun onPostTransform(context: TransformContext) { + this.transformers.forEach { transformer -> + this.threadMxBean.sumCpuTime(transformer) { + transformer.onPostTransform(context) + } + } + + val w1 = this.durations.keys.map { + it.javaClass.name.length + }.max() ?: 20 + this.durations.forEach { (transformer, ns) -> + println("${transformer.javaClass.name.padEnd(w1 + 1)}: ${ns / 1000000} ms") + } + } + + private fun ThreadMXBean.sumCpuTime(transformer: BaseDoKitClassTransformer, action: () -> R): R { + val ct0 = this.currentThreadCpuTime + val result = action() + val ct1 = this.currentThreadCpuTime + durations[transformer] = durations.getOrDefault(transformer, 0) + (ct1 - ct0) + return result + } + +} + diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/asmtransformer/DoKitAsmTransformer.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/asmtransformer/DoKitAsmTransformer.kt new file mode 100644 index 0000000000000000000000000000000000000000..c1ea8af5306a1361fb80ce36e7bba1c4c54ed06d --- /dev/null +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/asmtransformer/DoKitAsmTransformer.kt @@ -0,0 +1,17 @@ +package com.didichuxing.doraemonkit.plugin.asmtransformer + +import com.didichuxing.doraemonkit.plugin.asmclasstransformer.MethodStackDepTransformer +import com.didichuxing.doraemonkit.plugin.stack_method.MethodStackNodeUtil + +/** + * ================================================ + * 作 者:jint(金台) + * 版 本:1.0 + * 创建日期:2020/5/21-16:44 + * 描 述: + * 修订历史: + * ================================================ + */ +class DoKitAsmTransformer(val level: Int) : BaseDoKitAsmTransformer(MethodStackDepTransformer(level)) { + +} diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/BigImgTransformer.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/classtransformer/BigImgTransformer.kt similarity index 89% rename from Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/BigImgTransformer.kt rename to Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/classtransformer/BigImgTransformer.kt index e64125bebc5760b20e5e80cc3e9873489c2e355e..2f80ce386afdd5bcf816d4919318ee37b3661c08 100644 --- a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/BigImgTransformer.kt +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/classtransformer/BigImgTransformer.kt @@ -1,7 +1,7 @@ -package com.didichuxing.doraemonkit.plugin.transform +package com.didichuxing.doraemonkit.plugin.classtransformer import com.didichuxing.doraemonkit.plugin.DoKitExtUtil -import com.didichuxing.doraemonkit.plugin.methodExitInsnNode +import com.didichuxing.doraemonkit.plugin.getMethodExitInsnNodes import com.didiglobal.booster.annotations.Priority import com.didiglobal.booster.transform.TransformContext import com.didiglobal.booster.transform.asm.ClassTransformer @@ -25,10 +25,12 @@ import org.objectweb.asm.tree.VarInsnNode @Priority(2) @AutoService(ClassTransformer::class) class BigImgTransformer : ClassTransformer { - private val SHADOW_URL = "com/didichuxing/doraemonkit/aop/urlconnection/HttpUrlConnectionProxyUtil" - private val DESC = "(Ljava/net/URLConnection;)Ljava/net/URLConnection;" override fun transform(context: TransformContext, klass: ClassNode): ClassNode { +// if(klass.className == "com.didichuxing.doraemondemo.App"){ +// println("===BigImgTransformer====transform===") +// } + if (!DoKitExtUtil.dokitPluginSwitchOpen()) { return klass } @@ -49,8 +51,8 @@ class BigImgTransformer : ClassTransformer { (methodNode.name == "init" || methodNode.name == "") && methodNode.desc != null }.let { methodNode -> //函数结束的地方插入 - methodNode?.instructions?.methodExitInsnNode().let { - methodNode?.instructions?.insertBefore(it, createGlideInsnList()) + methodNode?.instructions?.getMethodExitInsnNodes()?.forEach { + methodNode.instructions?.insertBefore(it, createGlideInsnList()) } } } @@ -61,8 +63,8 @@ class BigImgTransformer : ClassTransformer { methodNode.name == "" && methodNode.desc != null }.let { methodNode -> //函数结束的地方插入 - methodNode?.instructions?.methodExitInsnNode().let { - methodNode?.instructions?.insertBefore(it, createPicassoInsnList()) + methodNode?.instructions?.getMethodExitInsnNodes()?.forEach { + methodNode.instructions?.insertBefore(it, createPicassoInsnList()) } } } diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/CommTransformer.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/classtransformer/CommTransformer.kt similarity index 92% rename from Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/CommTransformer.kt rename to Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/classtransformer/CommTransformer.kt index 4e752b12b407c37b12d517e7dba402b3042b6402..957afc7c7062c06e664f5386ac3afff55697fc30 100644 --- a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/CommTransformer.kt +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/classtransformer/CommTransformer.kt @@ -1,8 +1,8 @@ -package com.didichuxing.doraemonkit.plugin.transform +package com.didichuxing.doraemonkit.plugin.classtransformer import com.didichuxing.doraemonkit.plugin.DoKitExtUtil import com.didichuxing.doraemonkit.plugin.extension.SlowMethodExt -import com.didichuxing.doraemonkit.plugin.methodExitInsnNode +import com.didichuxing.doraemonkit.plugin.getMethodExitInsnNodes import com.didiglobal.booster.annotations.Priority import com.didiglobal.booster.transform.TransformContext import com.didiglobal.booster.transform.asm.ClassTransformer @@ -29,6 +29,9 @@ class CommTransformer : ClassTransformer { } override fun transform(context: TransformContext, klass: ClassNode): ClassNode { +// if(klass.className == "com.didichuxing.doraemondemo.App"){ +// println("===CommTransformer====transform===") +// } if (!DoKitExtUtil.dokitPluginSwitchOpen()) { return klass } @@ -78,15 +81,17 @@ class CommTransformer : ClassTransformer { val zeroConsMethodNode = klass.methods?.find { it.name == "" && it.desc == "()V" } - val zeroReturnInsnNode = zeroConsMethodNode?.instructions?.methodExitInsnNode() - zeroConsMethodNode?.instructions?.insertBefore(zeroReturnInsnNode, createOkHttpZeroConsInsnList()) + zeroConsMethodNode?.instructions?.getMethodExitInsnNodes()?.forEach { + zeroConsMethodNode.instructions.insertBefore(it, createOkHttpZeroConsInsnList()) + } //一个参数的构造方法 val oneConsMethodNode = klass.methods?.find { it.name == "" && it.desc == "(Lokhttp3/OkHttpClient;)V" } - val oneReturnInsnNode = oneConsMethodNode?.instructions?.methodExitInsnNode() - oneConsMethodNode?.instructions?.insertBefore(oneReturnInsnNode, createOkHttpOneConsInsnList()) + oneConsMethodNode?.instructions?.getMethodExitInsnNodes()?.forEach { + oneConsMethodNode.instructions.insertBefore(it, createOkHttpOneConsInsnList()) + } } //didi platform @@ -95,16 +100,18 @@ class CommTransformer : ClassTransformer { val zeroConsMethodNode = klass.methods?.find { it.name == "" && it.desc == "()V" } - val zeroReturnInsnNode = zeroConsMethodNode?.instructions?.methodExitInsnNode() - zeroConsMethodNode?.instructions?.insertBefore(zeroReturnInsnNode, createDidiHttpZeroConsInsnList()) + zeroConsMethodNode?.instructions?.getMethodExitInsnNodes()?.forEach { + zeroConsMethodNode.instructions.insertBefore(it, createDidiHttpZeroConsInsnList()) + } //一个参数的构造方法 val oneConsMethodNode = klass.methods?.find { it.name == "" && it.desc == "(Ldidihttp/DidiHttpClient;)V" } - val oneReturnInsnNode = oneConsMethodNode?.instructions?.methodExitInsnNode() - oneConsMethodNode?.instructions?.insertBefore(oneReturnInsnNode, createDidiHttpOneConsInsnList()) + oneConsMethodNode?.instructions?.getMethodExitInsnNodes()?.forEach { + oneConsMethodNode.instructions.insertBefore(it, createDidiHttpOneConsInsnList()) + } } } diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/classtransformer/EnterMethodStackTransformer.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/classtransformer/EnterMethodStackTransformer.kt new file mode 100644 index 0000000000000000000000000000000000000000..bad6b46c7f927702ff1397a1b6ca96bf8f3af2d2 --- /dev/null +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/classtransformer/EnterMethodStackTransformer.kt @@ -0,0 +1,162 @@ +package com.didichuxing.doraemonkit.plugin.classtransformer + +import com.didichuxing.doraemonkit.plugin.DoKitExtUtil +import com.didichuxing.doraemonkit.plugin.extension.SlowMethodExt +import com.didichuxing.doraemonkit.plugin.getMethodExitInsnNodes +import com.didichuxing.doraemonkit.plugin.ownerClassName +import com.didichuxing.doraemonkit.plugin.stack_method.MethodStackNode +import com.didichuxing.doraemonkit.plugin.stack_method.MethodStackNodeUtil +import com.didiglobal.booster.annotations.Priority +import com.didiglobal.booster.transform.TransformContext +import com.didiglobal.booster.transform.asm.ClassTransformer +import com.didiglobal.booster.transform.asm.asIterable +import com.didiglobal.booster.transform.asm.className +import com.google.auto.service.AutoService +import org.objectweb.asm.Opcodes.* +import org.objectweb.asm.tree.* + +/** + * ================================================ + * 作 者:jint(金台) + * 版 本:1.0 + * 创建日期:2020/5/14-18:07 + * 描 述:入口函数 慢函数调用栈 wiki:https://juejin.im/post/5e8d87c4f265da47ad218e6b + * 修订历史:不要指定自动注入 需要手动在DoKitAsmTransformer中通过配置创建 + * 原理:transform()方法的调用是无序的 原因:哪一个class会先被transformer执行是不确定的 但是每一个class被transformer执行顺序是遵循transformer的Priority规则的 + * ================================================ + */ +@Priority(4) +@AutoService(ClassTransformer::class) +class EnterMethodStackTransformer : ClassTransformer { + + private val thresholdTime = DoKitExtUtil.slowMethodExt.stackMethod.thresholdTime + private val level = 0 + override fun transform(context: TransformContext, klass: ClassNode): ClassNode { + if (!DoKitExtUtil.dokitPluginSwitchOpen()) { + return klass + } + + if (!DoKitExtUtil.slowMethodExt.methodSwitch) { + return klass + } + + if (DoKitExtUtil.slowMethodExt.strategy == SlowMethodExt.STRATEGY_NORMAL) { + return klass + } + + if (DoKitExtUtil.ignorePackageNames(klass.className)) { + return klass + } + + //默认为Application onCreate 和attachBaseContext + val enterMethods = DoKitExtUtil.slowMethodExt.stackMethod.enterMethods + //找不到配置的Application + if (enterMethods.isEmpty()) { + val superName = klass.superName + //先判断父类 + if (superName.isNotEmpty() && (superName == "android/app/Application" || + superName == "android/support/multidex/MultiDexApplication" || + superName == "androidx/multidex/MultiDexApplication")) { + klass.methods.filter { methodNode -> + (methodNode.name == "onCreate" && methodNode.desc == "()V") || (methodNode.name == "attachBaseContext" && methodNode.desc == "(Landroid/content/Context;)V") + }.let { methodNodes -> + //读取全是函数调用的Insn + methodNodes.forEach { methodNode -> + operateMethodInsn(klass, methodNode) + } + } + } + } else { + enterMethods.forEach { enterMethodName -> + klass.methods.forEach { methodNode -> + val allMethodName = "${klass.className}.${methodNode.name}" + if (allMethodName == enterMethodName) { + println("level===>$level mathched enterMethod===>$allMethodName") + operateMethodInsn(klass, methodNode) + } + } + } + } + + return klass + } + + + private fun operateMethodInsn(klass: ClassNode, methodNode: MethodNode) { + //读取全是函数调用的指令 + methodNode.instructions.asIterable().filterIsInstance(MethodInsnNode::class.java).filter { methodInsnNode -> + methodInsnNode.name != "" + }.forEach { methodInsnNode -> + val methodStackNode = MethodStackNode(level, methodInsnNode.ownerClassName, methodInsnNode.name, methodInsnNode.desc, klass.className, methodNode.name, methodNode.desc) + MethodStackNodeUtil.addMethodStackNode(level, methodStackNode) + } + //函数出入口插入耗时统计代码 + //方法入口插入 + methodNode.instructions.insert(createMethodEnterInsnList(level, klass.className, methodNode.name, methodNode.desc, methodNode.access)) + //方法出口插入 + methodNode.instructions.getMethodExitInsnNodes()?.forEach { methodExitInsnNode -> + methodNode.instructions.insertBefore(methodExitInsnNode, createMethodExitInsnList(level, klass.className, methodNode.name, methodNode.desc, methodNode.access)) + } + } + + + /** + * 创建慢函数入口指令集 + */ + private fun createMethodEnterInsnList(level: Int, className: String, methodName: String, desc: String, access: Int): InsnList { + val isStaticMethod = access and ACC_STATIC != 0 + val insnList = InsnList() + if (isStaticMethod) { + insnList.add(MethodInsnNode(INVOKESTATIC, "com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil", "getInstance", "()Lcom/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil;", false)) + insnList.add(IntInsnNode(BIPUSH, DoKitExtUtil.mStackMethodLevel)) + insnList.add(IntInsnNode(BIPUSH, thresholdTime)) + insnList.add(IntInsnNode(BIPUSH, level)) + insnList.add(LdcInsnNode(className)) + insnList.add(LdcInsnNode(methodName)) + insnList.add(LdcInsnNode(desc)) + insnList.add(MethodInsnNode(INVOKEVIRTUAL, "com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil", "recodeStaticMethodCostStart", "(IIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", false)) + } else { + insnList.add(MethodInsnNode(INVOKESTATIC, "com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil", "getInstance", "()Lcom/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil;", false)) + insnList.add(IntInsnNode(BIPUSH, DoKitExtUtil.mStackMethodLevel)) + insnList.add(IntInsnNode(BIPUSH, thresholdTime)) + insnList.add(IntInsnNode(BIPUSH, level)) + insnList.add(LdcInsnNode(className)) + insnList.add(LdcInsnNode(methodName)) + insnList.add(LdcInsnNode(desc)) + insnList.add(VarInsnNode(ALOAD, 0)) + insnList.add(MethodInsnNode(INVOKEVIRTUAL, "com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil", "recodeObjectMethodCostStart", "(IIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V", false)) + } + + return insnList + } + + + /** + * 创建慢函数退出时的指令集 + */ + private fun createMethodExitInsnList(level: Int, className: String, methodName: String, desc: String, access: Int): InsnList { + val isStaticMethod = access and ACC_STATIC != 0 + val insnList = InsnList() + if (isStaticMethod) { + insnList.add(MethodInsnNode(INVOKESTATIC, "com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil", "getInstance", "()Lcom/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil;", false)) + insnList.add(IntInsnNode(BIPUSH, thresholdTime)) + insnList.add(IntInsnNode(BIPUSH, level)) + insnList.add(LdcInsnNode(className)) + insnList.add(LdcInsnNode(methodName)) + insnList.add(LdcInsnNode(desc)) + insnList.add(MethodInsnNode(INVOKEVIRTUAL, "com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil", "recodeStaticMethodCostEnd", "(IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", false)) + } else { + insnList.add(MethodInsnNode(INVOKESTATIC, "com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil", "getInstance", "()Lcom/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil;", false)) + insnList.add(IntInsnNode(BIPUSH, thresholdTime)) + insnList.add(IntInsnNode(BIPUSH, level)) + insnList.add(LdcInsnNode(className)) + insnList.add(LdcInsnNode(methodName)) + insnList.add(LdcInsnNode(desc)) + insnList.add(VarInsnNode(ALOAD, 0)) + insnList.add(MethodInsnNode(INVOKEVIRTUAL, "com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil", "recodeObjectMethodCostEnd", "(IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V", false)) + } + return insnList + } + +} + diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/GlobalSlowMethodTransformer.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/classtransformer/GlobalSlowMethodTransformer.kt similarity index 92% rename from Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/GlobalSlowMethodTransformer.kt rename to Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/classtransformer/GlobalSlowMethodTransformer.kt index e94969550f323e820b12d48165ac4cf5fdc2fed9..d02de0053bd6ee9aef73ab9532500bf8157d0e08 100644 --- a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/GlobalSlowMethodTransformer.kt +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/classtransformer/GlobalSlowMethodTransformer.kt @@ -1,8 +1,8 @@ -package com.didichuxing.doraemonkit.plugin.transform +package com.didichuxing.doraemonkit.plugin.classtransformer import com.didichuxing.doraemonkit.plugin.DoKitExtUtil import com.didichuxing.doraemonkit.plugin.extension.SlowMethodExt -import com.didichuxing.doraemonkit.plugin.methodExitInsnNode +import com.didichuxing.doraemonkit.plugin.getMethodExitInsnNodes import com.didiglobal.booster.annotations.Priority import com.didiglobal.booster.transform.TransformContext import com.didiglobal.booster.transform.asm.ClassTransformer @@ -17,7 +17,7 @@ import org.objectweb.asm.tree.* * 作 者:jint(金台) * 版 本:1.0 * 创建日期:2020/5/14-18:07 - * 描 述:全局业务代码 慢函数 wiki:https://juejin.im/post/5e8d87c4f265da47ad218e6b + * 描 述:全局业务代码慢函数 wiki:https://juejin.im/post/5e8d87c4f265da47ad218e6b * 修订历史: * ================================================ */ @@ -25,7 +25,11 @@ import org.objectweb.asm.tree.* @AutoService(ClassTransformer::class) class GlobalSlowMethodTransformer : ClassTransformer { val thresholdTime = DoKitExtUtil.slowMethodExt.normalMethod.thresholdTime + override fun transform(context: TransformContext, klass: ClassNode): ClassNode { +// if(klass.className == "com.didichuxing.doraemondemo.App"){ +// println("===GlobalSlowMethodTransformer====transform===") +// } if (!DoKitExtUtil.dokitPluginSwitchOpen()) { return klass } @@ -56,7 +60,7 @@ class GlobalSlowMethodTransformer : ClassTransformer { //方法入口插入 methodNode.instructions.insert(createMethodEnterInsnList(className, methodNode.name, methodNode.access)) //方法出口插入 - methodNode.instructions.methodExitInsnNode().let { methodExitInsnNode -> + methodNode.instructions.getMethodExitInsnNodes()?.forEach { methodExitInsnNode -> methodNode.instructions.insertBefore(methodExitInsnNode, createMethodExitInsnList(className, methodNode.name, methodNode.access)) } } diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/UrlConnectionTransformer.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/classtransformer/UrlConnectionTransformer.kt similarity index 90% rename from Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/UrlConnectionTransformer.kt rename to Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/classtransformer/UrlConnectionTransformer.kt index dd5bf6a39c4d9e3534a9e2f2b1829caa9d42a494..cabe0fbcccbfa8e6f4ac8c112d0e7e63bc1e901f 100644 --- a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/UrlConnectionTransformer.kt +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/classtransformer/UrlConnectionTransformer.kt @@ -1,4 +1,4 @@ -package com.didichuxing.doraemonkit.plugin.transform +package com.didichuxing.doraemonkit.plugin.classtransformer import com.didichuxing.doraemonkit.plugin.DoKitExtUtil import com.didiglobal.booster.annotations.Priority @@ -28,6 +28,9 @@ class UrlConnectionTransformer : ClassTransformer { private val DESC = "(Ljava/net/URLConnection;)Ljava/net/URLConnection;" override fun transform(context: TransformContext, klass: ClassNode): ClassNode { +// if(klass.className == "com.didichuxing.doraemondemo.App"){ +// println("===UrlConnectionTransformer====transform===") +// } if (!DoKitExtUtil.dokitPluginSwitchOpen()) { return klass } diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/extension/DoKitExt.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/extension/DoKitExt.kt index 48dd0f432ef8f90089838aa1f2c695f25b87d118..949c7244c8f744fa15e2964044778cf582e06f89 100644 --- a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/extension/DoKitExt.kt +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/extension/DoKitExt.kt @@ -7,7 +7,6 @@ import org.gradle.api.Action */ open class DoKitExt(var dokitPluginSwitch: Boolean = true, var dokitLogSwitch: Boolean = true, - var usefulInRelease: Boolean = false, var comm: CommExt = CommExt(), var slowMethod: SlowMethodExt = SlowMethodExt()) { @@ -21,9 +20,6 @@ open class DoKitExt(var dokitPluginSwitch: Boolean = true, this.dokitLogSwitch = dokitLogSwitch } - fun usefulInRelease(usefulInRelease: Boolean) { - this.usefulInRelease = usefulInRelease - } /** * 让comm 支持 DSL 语法 @@ -44,7 +40,7 @@ open class DoKitExt(var dokitPluginSwitch: Boolean = true, } override fun toString(): String { - return "DoKitExt(dokitPluginSwitch=$dokitPluginSwitch, dokitLogSwitch=$dokitLogSwitch, usefulInRelease=$usefulInRelease, comm=$comm, slowMethod=$slowMethod)" + return "DoKitExt(dokitPluginSwitch=$dokitPluginSwitch, dokitLogSwitch=$dokitLogSwitch, comm=$comm, slowMethod=$slowMethod)" } diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/extension/SlowMethodExt.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/extension/SlowMethodExt.kt index 15a36085c46c6e1587dbcd5aeb301805cc0fd31b..c0cce06e7b9c9f5a21b54ba6c0ca202f852c9aca 100644 --- a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/extension/SlowMethodExt.kt +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/extension/SlowMethodExt.kt @@ -56,16 +56,16 @@ open class SlowMethodExt( this.thresholdTime = thresholdTime } + fun normalMethod(enterMethods: MutableSet) { this.enterMethods = enterMethods } override fun toString(): String { - return "StackMethodExt{" + - "thresholdTime=" + thresholdTime + - ", enterMethods=" + enterMethods + - '}' + return "StackMethodExt(thresholdTime=$thresholdTime, enterMethods=$enterMethods)" } + + } class NormalMethodExt( diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/processor/DoKitPluginConfigProcessor.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/processor/DoKitPluginConfigProcessor.kt index 886b2d32a9cc995c44b8a7426ae8ff5a3e59e3c7..004f6440ac3fc9f8df74c2297e83bcd0b7674577 100644 --- a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/processor/DoKitPluginConfigProcessor.kt +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/processor/DoKitPluginConfigProcessor.kt @@ -5,6 +5,7 @@ import com.android.build.gradle.api.BaseVariant import com.android.build.gradle.api.LibraryVariant import com.didichuxing.doraemonkit.plugin.DoKitExtUtil import com.didichuxing.doraemonkit.plugin.extension.DoKitExt +import com.didichuxing.doraemonkit.plugin.transform.* import com.didiglobal.booster.gradle.getAndroid import com.didiglobal.booster.gradle.isDynamicFeature import com.didiglobal.booster.gradle.project @@ -14,6 +15,7 @@ import com.didiglobal.booster.transform.ArtifactManager import com.didiglobal.booster.transform.artifacts import com.didiglobal.booster.transform.util.ComponentHandler import com.google.auto.service.AutoService +import org.gradle.api.Project import javax.xml.parsers.SAXParserFactory /** @@ -37,7 +39,6 @@ class DoKitPluginConfigProcessor : VariantProcessor { val parser = SAXParserFactory.newInstance().newSAXParser() val handler = ComponentHandler() parser.parse(manifest, handler) - //println("handler====>${handler.applications}") DoKitExtUtil.setApplications(handler.applications) } @@ -47,10 +48,9 @@ class DoKitPluginConfigProcessor : VariantProcessor { //查找Application路径 val doKitExt = variant.project.extensions.getByType(DoKitExt::class.java) DoKitExtUtil.init(doKitExt, appExt.defaultConfig.applicationId) - // println("doKitExt====>$doKitExt applicationId===>${appExt.defaultConfig.applicationId}") } - //println("variant====>${variant.name}") } + } \ No newline at end of file diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/stack_method/MethodStackNode.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/stack_method/MethodStackNode.kt new file mode 100644 index 0000000000000000000000000000000000000000..1cb88dcf9a6b074330c8e4b1050b873c4337c351 --- /dev/null +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/stack_method/MethodStackNode.kt @@ -0,0 +1,18 @@ +package com.didichuxing.doraemonkit.plugin.stack_method + +/** + * ================================================ + * 作 者:jint(金台) + * 版 本:1.0 + * 创建日期:2020/5/20-16:50 + * 描 述: + * 修订历史: + * ================================================ + */ +data class MethodStackNode(var level: Int, + var className: String, + var methodName: String, + var desc: String, + var parentClassName: String, + var parentMethodName: String, + var parentDesc: String) \ No newline at end of file diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/stack_method/MethodStackNodeUtil.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/stack_method/MethodStackNodeUtil.kt new file mode 100644 index 0000000000000000000000000000000000000000..b048260fa296ec7fae4ac9070afd6686a7d27e11 --- /dev/null +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/stack_method/MethodStackNodeUtil.kt @@ -0,0 +1,30 @@ +package com.didichuxing.doraemonkit.plugin.stack_method + +import org.gradle.internal.impldep.org.apache.commons.lang.mutable.Mutable +import java.util.* + +/** + * ================================================ + * 作 者:jint(金台) + * 版 本:1.0 + * 创建日期:2020/5/20-16:58 + * 描 述: + * 修订历史: + * ================================================ + */ +object MethodStackNodeUtil { + + + val METHOD_STACK_KEYS: MutableList> by lazy { + Collections.synchronizedList(mutableListOf>()) + } + + + fun addMethodStackNode(level: Int, methodStackNode: MethodStackNode) { + val key = "${methodStackNode.className}&${methodStackNode.methodName}&${methodStackNode.desc}" + METHOD_STACK_KEYS[level].add(key) + + } + + +} \ No newline at end of file diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitTransform.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/DoKitBaseTransform.kt similarity index 85% rename from Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitTransform.kt rename to Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/DoKitBaseTransform.kt index db4096992b333c9f548ee8d1961394663a719a01..3a4f00f40f2be8560fcde1e780737a62c4017a4e 100644 --- a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/DoKitTransform.kt +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/DoKitBaseTransform.kt @@ -1,4 +1,4 @@ -package com.didichuxing.doraemonkit.plugin +package com.didichuxing.doraemonkit.plugin.transform import com.android.build.api.transform.QualifiedContent import com.android.build.api.transform.Transform @@ -6,6 +6,7 @@ import com.android.build.api.transform.TransformInvocation import com.android.build.gradle.BaseExtension import com.android.build.gradle.internal.pipeline.TransformManager import com.android.build.gradle.internal.pipeline.TransformManager.SCOPE_FULL_PROJECT +import com.didichuxing.doraemonkit.plugin.DoKitTransformInvocation import com.didiglobal.booster.gradle.SCOPE_FULL_WITH_FEATURES import com.didiglobal.booster.gradle.SCOPE_PROJECT import com.didiglobal.booster.gradle.getAndroid @@ -16,15 +17,15 @@ import java.util.ServiceLoader /** * Represents the transform base - * + * DoKitCommTransform 作用于 CommTransformer、BigImgTransformer、UrlConnectionTransformer、GlobalSlowMethodTransformer * @author johnsonlee */ -open class DoKitTransform(val project: Project) : Transform() { +open class DoKitBaseTransform(val project: Project) : Transform() { /* * Preload transformers as List to fix NoSuchElementException caused by ServiceLoader in parallel mode */ - internal val transformers = ServiceLoader.load(Transformer::class.java, javaClass.classLoader).toList() + internal open val transformers = ServiceLoader.load(Transformer::class.java, javaClass.classLoader).toList() private val androidExt: BaseExtension = project.getAndroid() @@ -39,7 +40,7 @@ open class DoKitTransform(val project: Project) : Transform() { val bootKlassPool: AbstractKlassPool get() = androidKlassPool - override fun getName() = "booster" + override fun getName() = this.javaClass.simpleName override fun isIncremental() = true diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/DoKitCommTransform.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/DoKitCommTransform.kt new file mode 100644 index 0000000000000000000000000000000000000000..143a09f2a757b9b1a63624c918cd3612298c5d22 --- /dev/null +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/DoKitCommTransform.kt @@ -0,0 +1,12 @@ +package com.didichuxing.doraemonkit.plugin.transform + +import org.gradle.api.Project + +/** + * Represents the transform base + * DoKitCommTransform 作用于 CommTransformer、BigImgTransformer、UrlConnectionTransformer、GlobalSlowMethodTransformer、EnterMethodStackTransformer + * @author johnsonlee + */ +class DoKitCommTransform(androidProject: Project) : DoKitBaseTransform(androidProject) { + +} diff --git a/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/DoKitDependTransform.kt b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/DoKitDependTransform.kt new file mode 100644 index 0000000000000000000000000000000000000000..56e46360b34d4d091195361b2ae117fb27a22253 --- /dev/null +++ b/Android/buildSrc/src/main/kotlin/com/didichuxing/doraemonkit/plugin/transform/DoKitDependTransform.kt @@ -0,0 +1,19 @@ +package com.didichuxing.doraemonkit.plugin.transform + +import com.didichuxing.doraemonkit.plugin.asmtransformer.DoKitAsmTransformer +import com.didiglobal.booster.transform.Transformer +import org.gradle.api.Project + +/** + * Represents the transform base + * DoKitCommTransform 作用于 CommTransformer、BigImgTransformer、UrlConnectionTransformer、GlobalSlowMethodTransformer + * @author johnsonlee + */ +open class DoKitDependTransform(androidProject: Project, val level: Int) : DoKitBaseTransform(androidProject) { + + internal override val transformers = mutableListOf(DoKitAsmTransformer(level)) + + override fun getName(): String { + return "${this.javaClass.simpleName}_$level" + } +} diff --git a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/DoKitPlugin.java b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/DoKitPlugin.java index c140c28bd21dab1b726033d0aa4f331bb2544cfa..f0c1ebcdf72e1ca9c189247f92dea89c4dfb331e 100644 --- a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/DoKitPlugin.java +++ b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/DoKitPlugin.java @@ -2,15 +2,15 @@ package com.didichuxing.doraemonkit.plugin; import com.android.build.gradle.AppExtension; import com.didichuxing.doraemonkit.plugin.extension.DoKitExt; -import com.didichuxing.doraemonkit.plugin.transform.DokitBigImageTransform; -import com.didichuxing.doraemonkit.plugin.transform.DokitCommTransform; -import com.didichuxing.doraemonkit.plugin.transform.DokitMethodStack0Transform; -import com.didichuxing.doraemonkit.plugin.transform.DokitMethodStack1Transform; -import com.didichuxing.doraemonkit.plugin.transform.DokitMethodStack2Transform; -import com.didichuxing.doraemonkit.plugin.transform.DokitMethodStack3Transform; -import com.didichuxing.doraemonkit.plugin.transform.DokitMethodStack4Transform; -import com.didichuxing.doraemonkit.plugin.transform.DokitSlowMethodTransform; -import com.didichuxing.doraemonkit.plugin.transform.DokitUrlConnectionTransform; +import com.didichuxing.doraemonkit.plugin.classtransformer.DokitBigImageTransform; +import com.didichuxing.doraemonkit.plugin.classtransformer.DokitCommTransform; +import com.didichuxing.doraemonkit.plugin.classtransformer.DokitMethodStack0Transform; +import com.didichuxing.doraemonkit.plugin.classtransformer.DokitMethodStack1Transform; +import com.didichuxing.doraemonkit.plugin.classtransformer.DokitMethodStack2Transform; +import com.didichuxing.doraemonkit.plugin.classtransformer.DokitMethodStack3Transform; +import com.didichuxing.doraemonkit.plugin.classtransformer.DokitMethodStack4Transform; +import com.didichuxing.doraemonkit.plugin.classtransformer.DokitSlowMethodTransform; +import com.didichuxing.doraemonkit.plugin.classtransformer.DokitUrlConnectionTransform; import com.didiglobal.booster.gradle.BaseVariantKt; import com.didiglobal.booster.gradle.VariantScopeKt; diff --git a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitBigImageTransform.java b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitBigImageTransform.java index b39cb1977348be9d084b53ac0bc88f37e9874e63..3211dc10134a8fcaa632e9e859495c571066782b 100644 --- a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitBigImageTransform.java +++ b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitBigImageTransform.java @@ -1,4 +1,4 @@ -package com.didichuxing.doraemonkit.plugin.transform; +package com.didichuxing.doraemonkit.plugin.classtransformer; import com.android.build.api.transform.Context; import com.android.build.api.transform.TransformException; diff --git a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitCommTransform.java b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitCommTransform.java index 514cb9e6a826c8ecc38eac46d0d8638078e975f7..384f3d350422a4c0239a19e0e8b9c78e3a9ce672 100644 --- a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitCommTransform.java +++ b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitCommTransform.java @@ -1,4 +1,4 @@ -package com.didichuxing.doraemonkit.plugin.transform; +package com.didichuxing.doraemonkit.plugin.classtransformer; import com.android.build.api.transform.Context; import com.android.build.api.transform.TransformException; diff --git a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack0Transform.java b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack0Transform.java index 0f27a967907cbe739e865622273ca45d851c6628..3b87aee5ae1de03824d21b869ee3c91eab851f4d 100644 --- a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack0Transform.java +++ b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack0Transform.java @@ -1,4 +1,4 @@ -package com.didichuxing.doraemonkit.plugin.transform; +package com.didichuxing.doraemonkit.plugin.classtransformer; import com.android.build.api.transform.Context; import com.android.build.api.transform.TransformException; diff --git a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack1Transform.java b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack1Transform.java index 356cc239de95e31f0cdf7929d5000435b97e5f80..68f39c48d648db0884ac1e2a893504e4546a5788 100644 --- a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack1Transform.java +++ b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack1Transform.java @@ -1,4 +1,4 @@ -package com.didichuxing.doraemonkit.plugin.transform; +package com.didichuxing.doraemonkit.plugin.classtransformer; import com.android.build.api.transform.Context; import com.android.build.api.transform.TransformException; diff --git a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack2Transform.java b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack2Transform.java index 160f17cf7663c34a336a5da6712560f0f40453a1..40f0cb1417f050b8f1279d612763aa2492925922 100644 --- a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack2Transform.java +++ b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack2Transform.java @@ -1,4 +1,4 @@ -package com.didichuxing.doraemonkit.plugin.transform; +package com.didichuxing.doraemonkit.plugin.classtransformer; import com.android.build.api.transform.Context; import com.android.build.api.transform.TransformException; diff --git a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack3Transform.java b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack3Transform.java index c96c6645795051111f27af71d5e52547ff9decfb..26d3c6187e920c4dbd5309cb35820e7e4bb55a34 100644 --- a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack3Transform.java +++ b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack3Transform.java @@ -1,4 +1,4 @@ -package com.didichuxing.doraemonkit.plugin.transform; +package com.didichuxing.doraemonkit.plugin.classtransformer; import com.android.build.api.transform.Context; import com.android.build.api.transform.TransformException; diff --git a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack4Transform.java b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack4Transform.java index 1df3aa70d9f3194087a98963c59c61e03c1b3243..2c26a1e9c05ff06a190ec14d183c64839a9357e8 100644 --- a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack4Transform.java +++ b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitMethodStack4Transform.java @@ -1,4 +1,4 @@ -package com.didichuxing.doraemonkit.plugin.transform; +package com.didichuxing.doraemonkit.plugin.classtransformer; import com.android.build.api.transform.Context; import com.android.build.api.transform.TransformException; diff --git a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitSlowMethodTransform.java b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitSlowMethodTransform.java index 60b863f19e77eee2cca98d4c77e968f9e7c4c488..8a471f2a87a7d1c3d6c470bcbd7b84e52cc8d91f 100644 --- a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitSlowMethodTransform.java +++ b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitSlowMethodTransform.java @@ -1,4 +1,4 @@ -package com.didichuxing.doraemonkit.plugin.transform; +package com.didichuxing.doraemonkit.plugin.classtransformer; import com.android.build.api.transform.Context; import com.android.build.api.transform.TransformException; diff --git a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitUrlConnectionTransform.java b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitUrlConnectionTransform.java index df4f6ce5abaedd02b9295af7cfea5121d4f66677..caef349f32668b5f708ff0db26ef7915d6f9e44b 100644 --- a/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitUrlConnectionTransform.java +++ b/Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/transform/DokitUrlConnectionTransform.java @@ -1,4 +1,4 @@ -package com.didichuxing.doraemonkit.plugin.transform; +package com.didichuxing.doraemonkit.plugin.classtransformer; import com.android.build.api.transform.Context; import com.android.build.api.transform.TransformException; diff --git a/Android/doraemonkit/build.gradle b/Android/doraemonkit/build.gradle index 22e456a5950701a4422f871e6f81985beeaad85b..a2e572a1a7d2cc52a9a8e2a57fbb2d9c1e5da79c 100644 --- a/Android/doraemonkit/build.gradle +++ b/Android/doraemonkit/build.gradle @@ -67,7 +67,7 @@ dependencies { implementation rootProject.ext.dependencies["okhttp"] implementation rootProject.ext.dependencies["okhttp_v2"] implementation rootProject.ext.dependencies["room_runtime"] - annotationProcessor rootProject.ext.dependencies["room_compile"] + kapt rootProject.ext.dependencies["room_compile"] //三大图片框架 compileOnly rootProject.ext.dependencies["glide"] diff --git a/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/DoraemonKitReal.kt b/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/DoraemonKitReal.kt index 0c56bc0173c6fac5535ecd092a22d4c80396a598..f7a6462b090a329571e2ab8ac18991f1784af4a7 100644 --- a/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/DoraemonKitReal.kt +++ b/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/DoraemonKitReal.kt @@ -176,7 +176,7 @@ object DoraemonKitReal { * 添加内置kit */ private fun addInnerKit(application: Application) { - var json = "" + val json: String? if (FileUtils.isFileExists(DokitConstant.SYSTEM_KITS_BAK_PATH)) { json = FileIOUtils.readFile2String(DokitConstant.SYSTEM_KITS_BAK_PATH) } else { @@ -353,7 +353,7 @@ object DoraemonKitReal { return } val files = rootFileDir.listFiles() - for (file in files) { + files?.forEach { file -> if (file.isDirectory) { //若是目录,则递归打印该目录下的文件 //LogHelper.i(TAG, "文件夹==>" + file.getAbsolutePath()); @@ -372,6 +372,7 @@ object DoraemonKitReal { //LogHelper.i(TAG, "文件==>" + file.getAbsolutePath() + " fileName===>" + FileUtils.getFileName(file) + " fileLength===>" + fileLength); } } + } /** diff --git a/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil.java b/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil.java index 51fc8f89ec397a64c9fd24b0a8bacd20424968fc..ef0198b379d70aab73ddae8c940efbd9ba2fd1f2 100644 --- a/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil.java +++ b/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/aop/method_stack/MethodStackUtil.java @@ -9,6 +9,8 @@ import com.didichuxing.doraemonkit.aop.MethodCostUtil; import com.didichuxing.doraemonkit.kit.timecounter.TimeCounterManager; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.concurrent.ConcurrentHashMap; @@ -26,12 +28,13 @@ public class MethodStackUtil { /** * key className&methodName */ - private ConcurrentHashMap ROOT_METHOD_STACKS = new ConcurrentHashMap<>(); - private ConcurrentHashMap LEVEL1_METHOD_STACKS = new ConcurrentHashMap<>(); - private ConcurrentHashMap LEVEL2_METHOD_STACKS = new ConcurrentHashMap<>(); - private ConcurrentHashMap LEVEL3_METHOD_STACKS = new ConcurrentHashMap<>(); - private ConcurrentHashMap LEVEL4_METHOD_STACKS = new ConcurrentHashMap<>(); +// private ConcurrentHashMap ROOT_METHOD_STACKS = new ConcurrentHashMap<>(); +// private ConcurrentHashMap LEVEL1_METHOD_STACKS = new ConcurrentHashMap<>(); +// private ConcurrentHashMap LEVEL2_METHOD_STACKS = new ConcurrentHashMap<>(); +// private ConcurrentHashMap LEVEL3_METHOD_STACKS = new ConcurrentHashMap<>(); +// private ConcurrentHashMap LEVEL4_METHOD_STACKS = new ConcurrentHashMap<>(); + private List> METHOD_STACKS = Collections.synchronizedList(new ArrayList>()); /** * 静态内部类单例 @@ -44,39 +47,37 @@ public class MethodStackUtil { return MethodStackUtil.Holder.INSTANCE; } + private void createMethodStackList(int totalLevel) { + if (METHOD_STACKS.size() == totalLevel) { + return; + } + METHOD_STACKS.clear(); + for (int index = 0; index < totalLevel; index++) { + METHOD_STACKS.add(index, new ConcurrentHashMap()); + } + } + /** - * @param level + * @param currentLevel * @param methodName * @param classObj null 代表静态函数 */ - public void recodeObjectMethodCostStart(int thresholdTime, int level, String className, String methodName, String desc, Object classObj) { - + public void recodeObjectMethodCostStart(int totalLevel, int thresholdTime, int currentLevel, String className, String methodName, String desc, Object classObj) { try { + //先创建队列 + createMethodStackList(totalLevel); + MethodInvokNode methodInvokNode = new MethodInvokNode(); methodInvokNode.setStartTimeMillis(System.currentTimeMillis()); methodInvokNode.setCurrentThreadName(Thread.currentThread().getName()); methodInvokNode.setClassName(className); methodInvokNode.setMethodName(methodName); - if (level == 0) { - methodInvokNode.setLevel(0); - ROOT_METHOD_STACKS.put(String.format("%s&%s", className, methodName), methodInvokNode); - } else if (level == 1) { - methodInvokNode.setLevel(1); - LEVEL1_METHOD_STACKS.put(String.format("%s&%s", className, methodName), methodInvokNode); - } else if (level == 2) { - methodInvokNode.setLevel(2); - LEVEL2_METHOD_STACKS.put(String.format("%s&%s", className, methodName), methodInvokNode); - } else if (level == 3) { - methodInvokNode.setLevel(3); - LEVEL3_METHOD_STACKS.put(String.format("%s&%s", className, methodName), methodInvokNode); - } else if (level == 4) { - methodInvokNode.setLevel(4); - LEVEL4_METHOD_STACKS.put(String.format("%s&%s", className, methodName), methodInvokNode); - } + methodInvokNode.setLevel(currentLevel); + METHOD_STACKS.get(currentLevel).put(String.format("%s&%s", className, methodName), methodInvokNode); //特殊判定 - if (level == 0) { + if (currentLevel == 0) { if (classObj instanceof Application) { if (methodName.equals("onCreate")) { TimeCounterManager.get().onAppCreateStart(); @@ -95,36 +96,25 @@ public class MethodStackUtil { } /** - * @param level + * @param currentLevel * @param className * @param methodName * @param desc * @param classObj null 代表静态函数 */ - public void recodeObjectMethodCostEnd(int thresholdTime, int level, String className, String methodName, String desc, Object classObj) { + public void recodeObjectMethodCostEnd(int thresholdTime, int currentLevel, String className, String methodName, String desc, Object classObj) { synchronized (MethodCostUtil.class) { try { - MethodInvokNode methodInvokNode = null; - - if (level == 0) { - methodInvokNode = ROOT_METHOD_STACKS.get(String.format("%s&%s", className, methodName)); - } else if (level == 1) { - methodInvokNode = LEVEL1_METHOD_STACKS.get(String.format("%s&%s", className, methodName)); - } else if (level == 2) { - methodInvokNode = LEVEL2_METHOD_STACKS.get(String.format("%s&%s", className, methodName)); - } else if (level == 3) { - methodInvokNode = LEVEL3_METHOD_STACKS.get(String.format("%s&%s", className, methodName)); - } else if (level == 4) { - methodInvokNode = LEVEL4_METHOD_STACKS.get(String.format("%s&%s", className, methodName)); - } + MethodInvokNode methodInvokNode = METHOD_STACKS.get(currentLevel).get(String.format("%s&%s", className, methodName)); + if (methodInvokNode != null) { methodInvokNode.setEndTimeMillis(System.currentTimeMillis()); - bindNode(thresholdTime, level, methodInvokNode); + bindNode(thresholdTime, currentLevel, methodInvokNode); } //打印函数调用栈 - if (level == 0) { + if (currentLevel == 0) { if (methodInvokNode != null) { toStack(classObj instanceof Application, methodInvokNode); } @@ -139,7 +129,7 @@ public class MethodStackUtil { } //移除对象 - ROOT_METHOD_STACKS.remove(className + "&" + methodName); + METHOD_STACKS.get(0).remove(className + "&" + methodName); } } catch (Exception e) { @@ -155,18 +145,18 @@ public class MethodStackUtil { int index = 0; for (int i = 0; i < stackTraceElements.length; i++) { StackTraceElement stackTraceElement = stackTraceElements[i]; - if (currentClassName.equals(stackTraceElement.getClassName().replaceAll("\\.", "/")) && currentMethodName.equals(stackTraceElement.getMethodName())) { + if (currentClassName.equals(stackTraceElement.getClassName()) && currentMethodName.equals(stackTraceElement.getMethodName())) { index = i; break; } } StackTraceElement parentStackTraceElement = stackTraceElements[index + 1]; - return String.format("%s&%s", parentStackTraceElement.getClassName().replaceAll("\\.", "/"), parentStackTraceElement.getMethodName()); + return String.format("%s&%s", parentStackTraceElement.getClassName(), parentStackTraceElement.getMethodName()); } - private void bindNode(int thresholdTime, int level, MethodInvokNode methodInvokNode) { + private void bindNode(int thresholdTime, int currentLevel, MethodInvokNode methodInvokNode) { if (methodInvokNode == null) { return; } @@ -176,55 +166,24 @@ public class MethodStackUtil { return; } - MethodInvokNode parentMethodNode; - switch (level) { - case 1: - //设置父node 并将自己添加到父node中 - parentMethodNode = ROOT_METHOD_STACKS.get(getParentMethod(methodInvokNode.getClassName(), methodInvokNode.getMethodName())); - if (parentMethodNode != null) { - methodInvokNode.setParent(parentMethodNode); - parentMethodNode.addChild(methodInvokNode); - } - - break; - case 2: - //设置父node 并将自己添加到父node中 - parentMethodNode = LEVEL1_METHOD_STACKS.get(getParentMethod(methodInvokNode.getClassName(), methodInvokNode.getMethodName())); - if (parentMethodNode != null) { - methodInvokNode.setParent(parentMethodNode); - parentMethodNode.addChild(methodInvokNode); - } - break; - case 3: - //设置父node 并将自己添加到父node中 - parentMethodNode = LEVEL2_METHOD_STACKS.get(getParentMethod(methodInvokNode.getClassName(), methodInvokNode.getMethodName())); - if (parentMethodNode != null) { - methodInvokNode.setParent(parentMethodNode); - parentMethodNode.addChild(methodInvokNode); - } - break; - case 4: - //设置父node 并将自己添加到父node中 - parentMethodNode = LEVEL3_METHOD_STACKS.get(getParentMethod(methodInvokNode.getClassName(), methodInvokNode.getMethodName())); - if (parentMethodNode != null) { - methodInvokNode.setParent(parentMethodNode); - parentMethodNode.addChild(methodInvokNode); - } - break; - - default: - break; + if (currentLevel >= 1) { + MethodInvokNode parentMethodNode = METHOD_STACKS.get(currentLevel - 1).get(getParentMethod(methodInvokNode.getClassName(), methodInvokNode.getMethodName())); + if (parentMethodNode != null) { + methodInvokNode.setParent(parentMethodNode); + parentMethodNode.addChild(methodInvokNode); + } } + } - public void recodeStaticMethodCostStart(int thresholdTime, int level, String className, String methodName, String desc) { - recodeObjectMethodCostStart(thresholdTime, level, className, methodName, desc, new StaicMethodObject()); + public void recodeStaticMethodCostStart(int totalLevel, int thresholdTime, int currentLevel, String className, String methodName, String desc) { + recodeObjectMethodCostStart(totalLevel, thresholdTime, currentLevel, className, methodName, desc, new StaicMethodObject()); } - public void recodeStaticMethodCostEnd(int thresholdTime, int level, String className, String methodName, String desc) { - recodeObjectMethodCostEnd(thresholdTime, level, className, methodName, desc, new StaicMethodObject()); + public void recodeStaticMethodCostEnd(int thresholdTime, int currentLevel, String className, String methodName, String desc) { + recodeObjectMethodCostEnd(thresholdTime, currentLevel, className, methodName, desc, new StaicMethodObject()); } private void jsonTravel(List methodStackBeans, List methodInvokNodes) { @@ -254,7 +213,7 @@ public class MethodStackUtil { public void toJson() { List methodStackBeans = new ArrayList<>(); - for (MethodInvokNode methodInvokNode : ROOT_METHOD_STACKS.values()) { + for (MethodInvokNode methodInvokNode : METHOD_STACKS.get(0).values()) { MethodStackBean methodStackBean = new MethodStackBean(); methodStackBean.setCostTime(methodInvokNode.getCostTimeMillis()); methodStackBean.setFunction(methodInvokNode.getClassName() + "&" + methodInvokNode.getMethodName()); diff --git a/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/DokitManagerAdapter.kt b/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/DokitManagerAdapter.kt index dc266ea852dec551466a98f07b3dbb8bbbc417f4..eac3f11800a6f550ca9a58947e66eca03fc0afae 100644 --- a/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/DokitManagerAdapter.kt +++ b/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/DokitManagerAdapter.kt @@ -28,7 +28,7 @@ class DokitManagerAdapter(kitViews: MutableList?) override fun convert(holder: BaseViewHolder, item: KitWrapItem) { when (item.itemType) { KitWrapItem.TYPE_TITLE -> { - item.name?.let { + item.name.let { holder.getView(R.id.tv_title_name).text = it } } diff --git a/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/DokitManagerFragment.kt b/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/DokitManagerFragment.kt index 6e41ef543f7aad2998a5e2b67b7509d9af6b8591..4d5ad1cda34096d88b100493e38d4f01558c8fd9 100644 --- a/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/DokitManagerFragment.kt +++ b/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/DokitManagerFragment.kt @@ -343,7 +343,7 @@ class DokitManagerFragment : BaseFragment() { } - mAdapter.setOnItemClickListener { adapter, view, position -> + mAdapter.setOnItemClickListener { _, _, position -> if (IS_EDIT) { val multiKitItem = mKits[position] if (multiKitItem.itemType == KitWrapItem.TYPE_KIT) { diff --git a/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/DokitSettingAdapter.kt b/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/DokitSettingAdapter.kt index 9add4c38fc7297dee6e18eac452047db8306695d..626297f420789d35e9aaadae57b008fa0e43937c 100644 --- a/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/DokitSettingAdapter.kt +++ b/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/DokitSettingAdapter.kt @@ -18,6 +18,6 @@ class DokitSettingAdapter(datas: MutableList) : BaseQuickAdapter(R.layout.dk_item_main_setting, datas) { override fun convert(holder: BaseViewHolder, name: String) { - holder.getView(R.id.tv_name).setText(name) + holder.getView(R.id.tv_name).text = name } } \ No newline at end of file diff --git a/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/DokitSettingFragment.kt b/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/DokitSettingFragment.kt index 9fde9a724c7708232d57971547f808f4da9434ea..d006f26ce92587720ebcb1c320a1207869165ea0 100644 --- a/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/DokitSettingFragment.kt +++ b/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/DokitSettingFragment.kt @@ -45,7 +45,7 @@ class DokitSettingFragment : BaseFragment() { mAdapter = DokitSettingAdapter(mSettings) setting_list.adapter = mAdapter setting_list.layoutManager = LinearLayoutManager(activity) - mAdapter.setOnItemClickListener { adapter, view, position -> + mAdapter.setOnItemClickListener { _, _, position -> when (position) { 0 -> { diff --git a/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/ToolPanelAdapter.kt b/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/ToolPanelAdapter.kt index f0c9bc9c12c221d03ad939d8b39009120ef6a582..67e7ff67b3bedd01e37667e13c2d04833c1a998b 100644 --- a/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/ToolPanelAdapter.kt +++ b/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/ToolPanelAdapter.kt @@ -42,7 +42,7 @@ class ToolPanelAdapter(kitViews: MutableList?) override fun convert(holder: BaseViewHolder, item: KitWrapItem) { when (item.itemType) { KitWrapItem.TYPE_TITLE -> { - item.name?.let { + item.name.let { if (it.equals(DokitUtil.getString(R.string.dk_category_platform))) { holder.getView(R.id.tv_sub_title_name).visibility = View.VISIBLE holder.getView(R.id.tv_sub_title_name).text = "(www.dokit.cn)" @@ -64,7 +64,7 @@ class ToolPanelAdapter(kitViews: MutableList?) val radioGroup = holder.getView(R.id.rb_group) val rbNormal = holder.getView(R.id.rb_normal) val rbSystem = holder.getView(R.id.rb_system) - radioGroup.setOnCheckedChangeListener { group, checkedId -> + radioGroup.setOnCheckedChangeListener { _, checkedId -> if (checkedId == R.id.rb_normal) { //选中normal SharedPrefsUtil.putString(SharedPrefsKey.FLOAT_START_MODE, "normal") diff --git a/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/ToolPanelDokitView.kt b/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/ToolPanelDokitView.kt index b48ab27095b04639ba8d892cf87cf1a637fd7e9e..aa24b1d184936f759349c0adc754701d61387e7d 100644 --- a/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/ToolPanelDokitView.kt +++ b/Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/toolpanel/ToolPanelDokitView.kt @@ -114,7 +114,7 @@ class ToolPanelDokitView : AbsDokitView() { 4 } } - mAdapter.setOnItemClickListener { adapter, view, position -> + mAdapter.setOnItemClickListener { _, _, position -> val multiKitItem = mKits[position] if (multiKitItem.itemType == KitWrapItem.TYPE_KIT) { //常规模式下点击常用工具不隐藏工具面板 diff --git a/Android/gradle.properties b/Android/gradle.properties index 9a2427c08b2af1a2c7fd3b9263cb6a889125076f..d5870510d227ec8db3b36cb0d6a5d8437d431a67 100644 --- a/Android/gradle.properties +++ b/Android/gradle.properties @@ -16,3 +16,5 @@ android.debug.obsoleteApi=true android.useAndroidX=true android.enableJetifier=true android.injected.testOnly=false +#dokit 函数调用栈层级 +DoKit_MethodStack_Level=8