(二)Andfix的手写实现

在上一篇Andfix文章中(一)Andfix热修复原理中提到了,Andfix需要根据Android版本来维护,所以要适配不同的Android版本,这里根据Android5.1版本为例,简单介绍一下Andfix的手写实现。

一、生成修复后java类的dex文件

假如类A中的方法B有bug,新建一个A_fixed类,并添加一个B方法,这里的B方法是修复后的,然后重新编译,生成dex文件,在app/build/intermediates/javac/debug/complieDebugJavaWithJavac/classes/包名路径下有全部类的class,将完整包名文件夹都复制出来,然后文件夹中只留下修正后的类的class文件

用dx命令生成dex文件(需要配置环境变量,具体方法:

然后会在配置的路径下生成一个dex文件(将这个文件放到服务器)

二、创建一个DexManager管理类管理dex的替换

回到项目代码:

新建一个DexManager管理类管理dex的替换

//加载dex文件,拿到修复好的class文件
DexFile dexFile = DexFile.loadDex(file.getAbsolutePath(),new File(mContext.getCacheDir(),"opt").getAbsolutePath(),Context.MODE_PRIVATE);
Enumeration<String> entries = dexFile.entries();
while (entries.hasMoreElements()) {
  String className = entries.nextElement();
  Class fixedClass = dexFile.loadClass(className, mContext.getClassLoader());
  if (fixedClass != null) {
    fixClass(fixedClass);
  }
}

要拿到修正的方法,就要在修正后的方法中添加自定义注解,告诉程序这个方法对应要替换的是哪个类的那个方法,自定义注解如下:

@MethodReplace(className = "包名.A",methodName = "B")

fixClass(Class fixClazz) 找到方法并替换:

				Method[] methods = fixClazz.getDeclaredMethods();
        MethodReplace methodReplace;
        String className;
        String methodName;
        Class<?> bugClass;
        Method bugMethod;
        for (Method fixMethod : methods) {
            methodReplace = fixMethod.getAnnotation(MethodReplace.class);
            if (methodReplace == null) {
                continue;
            }
            Log.e(TAG, "找到修复好的方法: " + fixMethod.getDeclaringClass() + "@" + fixMethod.getName());
            className = methodReplace.className();
            methodName = methodReplace.methodName();
            if (!TextUtils.isEmpty(className) && !TextUtils.isEmpty(methodName)) {
                try {
                    bugClass = Class.forName(className);
                    bugMethod =
                            bugClass.getDeclaredMethod(methodName, fixMethod.getParameterTypes());
                    replace(bugMethod, fixMethod);
                    Log.e(TAG, "修复完成!");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }else {
                Log.e(TAG, "/修复好的方法未设置自定义注解属性");
            }
        }

其中的replace是native方法:

private native void replace(Method bugMethod, Method fixMethod);

native层代码,利用ArtMethod结构体,实现方法替换:

extern "C"
JNIEXPORT void JNICALL
Java_com_netease_andfix_DexManager_replace(JNIEnv *env, jobject instance, jobject bugMethod,
                                           jobject fixMethod) {
    env->FindClass()
    //ba获得指向被替换的目标方法的指针(有bug的方法的指针)
    art::mirror::ArtMethod *bugArtMethod = reinterpret_cast(env->FromReflectedMethod(
            bugMethod));
    //获得指向新的方法的指针(被修复了的方法的指针)
    art::mirror::ArtMethod *fixArtMethod = reinterpret_cast(env->FromReflectedMethod(
            fixMethod));
    reinterpret_cast(fixArtMethod->declaring_class_)->class_loader_ =
            reinterpret_cast(bugArtMethod->declaring_class_)->class_loader_; //for plugin classloader
    reinterpret_cast(fixArtMethod->declaring_class_)->clinit_thread_id_ =
            reinterpret_cast(bugArtMethod->declaring_class_)->clinit_thread_id_;
    reinterpret_cast(fixArtMethod->declaring_class_)->status_ =
            reinterpret_cast(bugArtMethod->declaring_class_)->status_ - 1;
    reinterpret_cast(fixArtMethod->declaring_class_)->super_class_ = 0;
    //把就函数的成员变量替换为新函数的
    bugArtMethod->declaring_class_ = fixArtMethod->declaring_class_;
    bugArtMethod->dex_cache_resolved_methods_ = fixArtMethod->dex_cache_resolved_methods_;
    bugArtMethod->access_flags_ = fixArtMethod->access_flags_;
    bugArtMethod->dex_cache_resolved_types_ = fixArtMethod->dex_cache_resolved_types_;
    bugArtMethod->dex_code_item_offset_ = fixArtMethod->dex_code_item_offset_;
    bugArtMethod->method_index_ = fixArtMethod->method_index_;
    bugArtMethod->dex_method_index_ = fixArtMethod->dex_method_index_;

    bugArtMethod->ptr_sized_fields_.entry_point_from_interpreter_ = fixArtMethod->ptr_sized_fields_.entry_point_from_interpreter_;
    bugArtMethod->ptr_sized_fields_.entry_point_from_jni_ = fixArtMethod->ptr_sized_fields_.entry_point_from_jni_;
    bugArtMethod->ptr_sized_fields_.entry_point_from_quick_compiled_code_ = fixArtMethod->ptr_sized_fields_.entry_point_from_quick_compiled_code_;
    __android_log_print(ANDROID_LOG_ERROR, "AndFix","replace_5_1: %d , %d",
                        static_cast(bugArtMethod->ptr_sized_fields_.entry_point_from_quick_compiled_code_),
                        fixArtMethod->ptr_sized_fields_.entry_point_from_quick_compiled_code_);

}

你可能感兴趣的:(android开发学习记录)