继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

android jvmti 应用之实现android studio 3.5 apply change功能(不重启的热修复哦)

霁雪清虹
关注TA
已关注
手记 33
粉丝 1万
获赞 137

上一篇使用了jvmti 完成了计算objecSize的功能,这次重点介绍一下如何实现android studio 3.5 apply change 功能,即如何在不重启应用的前提下运行时修改class,这里提一点android jvmti 是android p才开始提供的,然后只能运用于debug

1. 效果图

out.dex中存放着修复之后的Test.class log输出为 修复的Test,然后最爽的一点是运行时修改class,无需重启哟~!!!

2. show code

代码地址 https://github.com/zjw-swun/JVMTI_Demo
喜欢就给个star吧,本代码fork自dodola大佬的https://github.com/AndroidAdvanceWithGeektime/JVMTI_Sample,再次感谢
代码位置MainActivity中

 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方法

native-lib.cpp

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,阅读手记
1人推荐
发表评论
随时随地看视频慕课网APP