上一篇使用了jvmti 完成了計算objecSize的功能,此次重點介紹一下如何實現android studio 3.5 apply change 功能,即如何在不重啓應用的前提下運行時修改class,這裏提一點android jvmti 是android p纔開始提供的,而後只能運用於debugjava
out.dex中存放着修復以後的Test.class log輸出爲 修復的Test,而後最爽的一點是運行時修改class,無需重啓喲~!!!android
代碼地址 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.cpp
中bash
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);
}
複製代碼
代碼中已實現 MethoddEntry,對方法調用的hook能打印函數調用棧, 實現了獲取classLoader加載的全部類信息app