booster功能分析(1)

一、代碼總體結構

buildSrc是gradle界定的用來作統一編譯的一種配置方式,代碼中除了booster-android-instrument方面的代碼都適用這個方式來進行統一依賴。 html

而且自定義了個plugin來作相對應的一些內容生成,對項目中的java、groovy、kotlin依賴自定義的task:generateBuildProps來生成相對應的build.java文件用來保存一些信息,好比下方的:

booster-gradle-api、booster-gradle-v3_0 booster-gradle-v3_二、booster-gradle-v3_3 是一些擴展類java

booster-gradle-plugin、booster-transform-asm 這裏是booster的主要入口,用來進行插莊等操做都須要經過這裏來進入android

booster-android-api、booster-android-instrument這些就是提供插莊所須要的類,好比booster-android-instrument-toast對toast進行功能修改,來防止一些系統致使的toast錯誤api

二、功能細分

(1)ToastBugFix

經過asm的方式替換系統的實現來完成系統bug修復的功能。具體實現以下:bash

如上面所看到,經過遍歷class的節點中是否有包名等於當前所要插莊的代碼則返回,不然進行方法遍歷查找,若是等於系統的toast,則進行代碼的插莊替換,具體看MethodInsnNode.optimize這個方法裏面。接下來看替換的toast作了什麼操做

代碼中能夠看出,在替換實現的方式內部,當sdk版本號大於25的時候會執行workaround的方法,會經過反射的方式去獲取到toast中的handler和mShow方法,再經過反射去添加一個回調,CaughtCallback,這個callback作了下面的操做:

看完代碼是否是以爲很簡單,只是在裏面加了個try catch就能夠修復系統的bug。

(2)FinalizerWatchdog finalize time out 的解決方案

val method = klass.methods?.find {
    "${it.name}${it.desc}" == "attachBaseContext(Landroid/content/Context;)V"} ?:klass.defaultAttachBaseContext
    
       method.instructions?.findAll(RETURN, ATHROW)?.forEach {
    method.instructions?.insertBefore(it, MethodInsnNode(INVOKESTATIC, FINALIZER_WATCHDOG_DAEMON_KILLER, "kill", "()V", false))
    logger.println(" + $FINALIZER_WATCHDOG_DAEMON_KILLER.kill()V before @${if (it.opcode == ATHROW) "athrow" else "return"}: ${klass.name}.${method.name}${method.desc} ")
    }
複製代碼

FinalizerWatchdogDaemonKiller這個的職責就是最多嘗試10次,查找java.lang.Daemons$FinalizerWatchdogDaemon這個類,去作反射操做獲取他的getinstance,並設置他的thread爲空,若是失敗就調用stop方法來執行。 可是反射若是上面那個連接所說的,Android 9.0 版本開始限制 Private API 調用,不能再使用反射調用 Daemons 以及 FinalizerWatchdogDaemon 類方法,因此這塊應該還能夠再優化。app

(3)Thread

主要是經過查找如下幾種類型對thread的調用來進行代碼插莊操做ide

一、 transformInvokeVirtual,檢測是調用Thread.start或者Thread.setName,則進行插莊替換實現進行線程的名字替換post

if (context.klassPool.get(THREAD).isAssignableFrom(this.owner)) {
        when ("${this.name}${this.desc}") {
            "start()V" -> {
                method.instructions.insertBefore(this, LdcInsnNode(makeThreadName(klass.className)))
                method.instructions.insertBefore(this, MethodInsnNode(Opcodes.INVOKESTATIC, SHADOW_THREAD, "setThreadName", "(Ljava/lang/Thread;Ljava/lang/String;)Ljava/lang/Thread;", false))
                logger.println(" + $SHADOW_THREAD.makeThreadName(Ljava/lang/String;Ljava/lang/String;) => ${this.owner}.${this.name}${this.desc}: ${klass.name}.${method.name}${method.desc}")
                this.owner = THREAD
            }
            "setName(Ljava/lang/String;)V" -> {
                method.instructions.insertBefore(this, LdcInsnNode(makeThreadName(klass.className)))
                method.instructions.insertBefore(this, MethodInsnNode(Opcodes.INVOKESTATIC, SHADOW_THREAD, "makeThreadName", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false))
                logger.println(" + $SHADOW_THREAD.makeThreadName(Ljava/lang/String;Ljava/lang/String;) => ${this.owner}.${this.name}${this.desc}: ${klass.name}.${method.name}${method.desc}")
                this.owner = THREAD
            }
        }
    }
複製代碼

二、transformInvokeSpecial,符合如下一種狀況的方法,也進行名字的從新設定gradle

if (this.owner == THREAD && this.name == "<init>") {
            when (this.desc) {
                "()V",
                "(Ljava/lang/Runnable;)V",
                "(Ljava/lang/ThreadGroup;Ljava/lang/Runnable;)V" -> {
                    method.instructions.insertBefore(this, LdcInsnNode(makeThreadName(klass.className)))
                    val r = this.desc.lastIndexOf(')')
                    val desc = "${this.desc.substring(0, r)}Ljava/lang/String;${this.desc.substring(r)}"
                    logger.println(" + $SHADOW_THREAD.makeThreadName(Ljava/lang/String;Ljava/lang/String;) => ${this.owner}.${this.name}${this.desc}: ${klass.name}.${method.name}${method.desc}")
                    logger.println(" * ${this.owner}.${this.name}${this.desc} => ${this.owner}.${this.name}$desc: ${klass.name}.${method.name}${method.desc}")
                    this.desc = desc
                }
                "(Ljava/lang/String;)V",
                "(Ljava/lang/ThreadGroup;Ljava/lang/String;)V",
                "(Ljava/lang/Runnable;Ljava/lang/String;)V",
                "(Ljava/lang/ThreadGroup;Ljava/lang/Runnable;Ljava/lang/String;)V" -> {
                    method.instructions.insertBefore(this, LdcInsnNode(makeThreadName(klass.className)))
                    method.instructions.insertBefore(this, MethodInsnNode(Opcodes.INVOKESTATIC, SHADOW_THREAD, "makeThreadName", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false))
                    logger.println(" + $SHADOW_THREAD.makeThreadName(Ljava/lang/String;Ljava/lang/String;) => ${this.owner}.${this.name}${this.desc}: ${klass.name}.${method.name}${method.desc}")
                }
                "(Ljava/lang/ThreadGroup;Ljava/lang/Runnable;Ljava/lang/String;J)V" -> {
                    method.instructions.insertBefore(this, InsnNode(Opcodes.POP2)) // discard the last argument: stackSize
                    method.instructions.insertBefore(this, LdcInsnNode(makeThreadName(klass.className)))
                    method.instructions.insertBefore(this, MethodInsnNode(Opcodes.INVOKESTATIC, SHADOW_THREAD, "makeThreadName", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false))
                    logger.println(" + $SHADOW_THREAD.makeThreadName(Ljava/lang/String;Ljava/lang/String;) => ${this.owner}.${this.name}${this.desc}: ${klass.name}.${method.name}${method.desc}")
                    this.desc = "(Ljava/lang/ThreadGroup;Ljava/lang/Runnable;Ljava/lang/String;)V"
                }
            }
        }
複製代碼

三、transformInvokeStatic,若是是經過線程池方式建立的線程,統一替換成ShadowExecutors來建立線程,保證所產生的線程名字等信息可以統一優化

when (this.owner) {
            EXECUTORS -> {
                when (this.name) {
                    //往opcode棧push String常量值 "\u200B"+類名
                    "defaultThreadFactory" -> {
                        val r = this.desc.lastIndexOf(')')
                        val desc = "${this.desc.substring(0, r)}Ljava/lang/String;${this.desc.substring(r)}"
                        logger.println(" * ${this.owner}.${this.name}${this.desc} => $SHADOW_EXECUTORS.${this.name}$desc: ${klass.name}.${method.name}${method.desc}")
                        this.owner = SHADOW_EXECUTORS
                        this.desc = desc
                        method.instructions.insertBefore(this, LdcInsnNode(makeThreadName(klass.className)))
                    }
                    "newCachedThreadPool",
                    "newFixedThreadPool",
                    "newSingleThreadExecutor",
                    "newSingleThreadScheduledExecutor",
                    "newScheduledThreadPool" -> {
                        val r = this.desc.lastIndexOf(')')
                        val name = this.name.replace("new", "newOptimized")
                        val desc = "${this.desc.substring(0, r)}Ljava/lang/String;${this.desc.substring(r)}"
                        logger.println(" * ${this.owner}.${this.name}${this.desc} => $SHADOW_EXECUTORS.$name$desc: ${klass.name}.${method.name}${method.desc}")
                        this.owner = SHADOW_EXECUTORS
                        this.name = name
                        this.desc = desc
                        method.instructions.insertBefore(this, LdcInsnNode(makeThreadName(klass.className)))
                    }
                }
            }
        }
複製代碼

(4)ActivityThread 獲取handler的子類H,經過ActivityThreadHooker往裏面埋入hook方法,來設置callback,用自定義callback的來替換系統的callback,以此來捕獲系統致使的異常

override fun transform(context: TransformContext, klass: ClassNode): ClassNode {
        if (!this.applications.contains(klass.className)) {
            return klass
        }

        mapOf(
            "<clinit>()V" to klass.defaultClinit,
            "<init>()V" to klass.defaultInit,
            "onCreate()V" to klass.defaultOnCreate
        ).forEach { (unique, defaultMethod) ->
            val method = klass.methods?.find {
                "${it.name}${it.desc}" == unique
            } ?: defaultMethod.also {
                klass.methods.add(it)
            }
            method.instructions?.findAll(RETURN, ATHROW)?.forEach {
                method.instructions?.insertBefore(it, MethodInsnNode(INVOKESTATIC, ACTIVITY_THREAD_HOOKER, "hook", "()V", false))
                logger.println(" + $ACTIVITY_THREAD_HOOKER.hook()V before @${if (it.opcode == ATHROW) "athrow" else "return"}: ${klass.name}.${method.name}${method.desc}")
            }
        }

        return klass
    }
複製代碼

未完待續

相關文章
相關標籤/搜索