关于AndFix的实现原理。
1. 创建无bug的dex。
2. 放入到工程中。
3. 通过java代码把dex存放到安装目录的文件夹下。
4. 加载dex。
5. 通过jni层进行方法替换。
java层关键代码:
DexFile dexFile1 = DexFile.loadDex(dexFile.getAbsolutePath(),okDexFile.getAbsolutePath(),Context.MODE_PRIVATE);// load dex
Enumeration<String> entries = dexFile1.entries();// 对load的类进行遍历。
while ( entries.hasMoreElements()){// 遍历类
String key = entries.nextElement();
Class<?> okClass = dexFile1.loadClass(key,getClass().getClassLoader());// 获取类
if(okClass ==null ){
continue;
}
findBugMethod(okClass);
}
private void findBugMethod(Class<?> okClass){
// 获取该类中的所有方法。
Method[] methods = okClass.getDeclaredMethods();
for(Method method:methods){
// 获取注解。已经指明注解类型。
MethodReplace methodReplace = method.getAnnotation(MethodReplace.class);
if(methodReplace == null){
continue;
}
// 将要修复的错误类和错误方法
String bugClassName = methodReplace.className();
String bugMethodName = methodReplace.methodName();
// 获取Bug Method 实例.也就是该方法的标识。不一定是实例参数.
// 该方法在内存卡的映射地址
try {
Method bugMethod = Class.forName(bugClassName).getDeclaredMethod(bugMethodName,method.getParameterTypes());
if(bugMethod != null){
replaceArt(bugMethod,method);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
C层实现。进行方法替换。
ArtMethod* smeth = (ArtMethod*)env->FromReflectedMethod(jobject2);
ArtMethod* dmeth = (ArtMethod*)env->FromReflectedMethod(jobject3);
smeth->declaring_class_=dmeth->declaring_class_;
smeth->dex_cache_resolved_types_=dmeth->dex_cache_resolved_types_;
smeth->access_flags_=dmeth->access_flags_;
smeth->dex_cache_resolved_methods_=dmeth->dex_cache_resolved_methods_;
smeth->dex_code_item_offset_=dmeth->dex_code_item_offset_;
smeth->method_index_=dmeth->method_index_;
smeth->dex_method_index_=dmeth->dex_method_index_;
smeth->ptr_sized_fields_.entry_point_from_interpreter_=dmeth->ptr_sized_fields_.entry_point_from_interpreter_;
smeth->ptr_sized_fields_.entry_point_from_jni_=dmeth->ptr_sized_fields_.entry_point_from_jni_;
smeth->ptr_sized_fields_.entry_point_from_quick_compiled_code_=dmeth->ptr_sized_fields_.entry_point_from_quick_compiled_code_;
注意点:
1. 需要错误类已经有实例。也就是已经实例化。静态的未尝试。