android jvmti 應用之實現android studio 3.5 apply change功能(不重啓的熱修復哦)

上一篇使用了jvmti 完成了計算objecSize的功能,此次重點介紹一下如何實現android studio 3.5 apply change 功能,即如何在不重啓應用的前提下運行時修改class,這裏提一點android jvmti 是android p纔開始提供的,而後只能運用於debugjava

1. 效果圖

out.dex中存放着修復以後的Test.class log輸出爲 修復的Test,而後最爽的一點是運行時修改class,無需重啓喲~!!!android

2. show code

代碼地址 github.com/zjw-swun/JV… 喜歡就給個star吧,本代碼fork自dodola大佬的github.com/AndroidAdva…,再次感謝 代碼位置MainActivity中git

button_modify_class.setOnClickListener {
            // redefineClass:對於已經加載的類從新進行轉換處理,即會觸發從新加載類定義,
            // 須要注意的是,新加載的類不能修改舊有的類聲明,譬如不能增長屬性、不能修改方法聲明
            Test().log()
            JVMTIHelper.init(this@MainActivity)
            //dexbyte
            val dexbyte = getBytes(assets.open("out.dex"))
            JVMTIHelper.redefineClass(Test::class.java, dexbyte)
            Test().log()
        }
複製代碼

重點就是這句話JVMTIHelper.redefineClass(Test::class.java, dexbyte)調用了jni封裝的jvmti的redefineClass方法github

native-lib.cppbash

extern "C" JNIEXPORT jint JNICALL redefineClass(JNIEnv *env, jclass clazz, jclass target, jbyteArray dex_bytes) {
    ALOGI("==========redefineClass =======");
    jvmtiClassDefinition def;
    def.klass = target;
    def.class_byte_count = static_cast<jint>(env->GetArrayLength(dex_bytes));

    signed char *redef_bytes = env->GetByteArrayElements(dex_bytes, nullptr);
    jvmtiError res = localJvmtiEnv->Allocate(def.class_byte_count,
                                             const_cast<unsigned char **>(&def.class_bytes));
    if (res != JVMTI_ERROR_NONE) {
        return static_cast<jint>(res);
    }
    memcpy(const_cast<unsigned char *>(def.class_bytes), redef_bytes, def.class_byte_count);
    env->ReleaseByteArrayElements(dex_bytes, redef_bytes, 0);
    // Do the redefinition.
    res = localJvmtiEnv->RedefineClasses(1, &def);
    return static_cast<jint>(res);
}
複製代碼

3. 關於JVMTI的更多功能函數有空再探索(jvmti超級適合Android APM,賽高!!!)

代碼中已實現 MethoddEntry,對方法調用的hook能打印函數調用棧, 實現了獲取classLoader加載的全部類信息app

相關文章
相關標籤/搜索