AndFix解析——(下)
来源:互联网 发布:涉密网络分级保护 编辑:程序博客网 时间:2024/06/06 09:08
我们接着分析阿里开源的AndFix库, 上一篇分析了Patch
类,这个类相当于我们提供补丁的容器,容器里有了东西,我们要对容器进行操作了, 于是开始了我们这次的分析。
在第二篇里,我们添了Patch
类的那个坑,那么这篇文章我们就把最后两个坑填一填,即loadPatch()
方法和AndFixManager
类。
在阿里给的Demo里,我们还有最后的loadPatch()
方法没有深入,所以先从loadPatch()
方法开始。
PatchManager loadPatch()
public void loadPatch() {mLoaders.put("*", mContext.getClassLoader());// wildcardSet<String> patchNames;List<String> classes;for (Patch patch : mPatchs) {patchNames = patch.getPatchNames();for (String patchName : patchNames) {classes = patch.getClasses(patchName);mAndFixManager.fix(patch.getFile(),mContext.getClassLoader(), classes);}}}
不知道大家是否还记得之前提到的mLoaders
这个成员变量,隔了这么久,说实话我也忘记了,在这里我先带大家一起回忆一下, private final Map<String, ClassLoader> mLoaders;
,mLoaders
原来是储存不同ClassLoader
的Map啊。 好的,我们继续向下进行,在第一篇,通过private的initPatchs()
方法,和public的addPatch()
方法,将Patch
加入了mPatchs
这个List
, 所以,这里只要去遍历这个List
,来获取不同的Patch
,并对每个Patch
做操作即可。 每个Patch
,代表了一个.apatch
的文件,getClasses(patchName)
代表着这个patch
的patchName
对应的所有需要修改的类。 patchName
从两方面而来,一个是你用apkpatch.jar
的时候使用-n选项指定或者默认的,另外一个方面是写入Manifest
的时候以 -Classes
结尾的key,这个我暂时还没有遇到过,遇到过的同学可以给我讲讲,抱歉博客暂时没有评论功能,可以发邮件给我,airzhaoyn@gmail.com。
好了,这里讲的差不多了,我们继续深入。 可以看到,获取了一个patchName
对应的所有的需要修改的类后,就会调用AndFixManager
类的fix(File, ClassLoader,List<String>)
方法, 先来看看源码
AndFixManager fix(File, ClassLoader,List)
/** * fix * * @param file * patch file * @param classLoader * classloader of class that will be fixed * @param classes * classes will be fixed */public synchronized void fix(File file, ClassLoader classLoader,List<String> classes) {//是否是支持的Android版本(在AndFixManager类初始化的时候会修改mSupport变量)if (!mSupport) {return;} //验证这个文件的签名和此应用是否一致if (!mSecurityChecker.verifyApk(file)) {// security check failreturn;}//这段代码的源码中的注释很清楚,我就不写了File optfile = new File(mOptDir, file.getName());boolean saveFingerprint = true;if (optfile.exists()) {// need to verify fingerprint when the optimize file exist,// prevent someone attack on jailbreak device with// Vulnerability-Parasyte.// btw:exaggerated android Vulnerability-Parasyte// http://secauo.com/Exaggerated-Android-Vulnerability-Parasyte.htmlif (mSecurityChecker.verifyOpt(optfile)) {saveFingerprint = false;} else if (!optfile.delete()) {return;}} //startfinal DexFile dexFile = DexFile.loadDex(file.getAbsolutePath(),optfile.getAbsolutePath(), Context.MODE_PRIVATE);if (saveFingerprint) {mSecurityChecker.saveOptSig(optfile);}ClassLoader patchClassLoader = new ClassLoader(classLoader) {@Overrideprotected Class<?> findClass(String className)throws ClassNotFoundException {Class<?> clazz = dexFile.loadClass(className, this);if (clazz == null&& className.startsWith("com.alipay.euler.andfix")) {return Class.forName(className);// annotation’s class// not found}if (clazz == null) {throw new ClassNotFoundException(className);}return clazz;}};//Enumerate the names of the classes in this DEX file.Enumeration<String> entrys = dexFile.entries();Class<?> clazz = null;while (entrys.hasMoreElements()) {String entry = entrys.nextElement();if (classes != null && !classes.contains(entry)) {continue;// skip, not need fix}clazz = dexFile.loadClass(entry, patchClassLoader);if (clazz != null) {fixClass(clazz, classLoader);}}}
对这部分的源码解析,从源码中标注//start开始。 我们先看一下DexFile是什么,官方文档这样说:Manipulates DEX files. It is used primarily by class loaders.
就是主要被类加载器使用的操作Dex文件的类。 好了,我们可以继续看源码了,先获取一个DexFile对象的,然后通过匿名内部类实现了一个ClassLoaders的子类,遍历这个Dex文件中所有的类, 如果需要修改的类集合(即从PatchManager loadPatch()
方法中传过来的类集合)中在这个Dex文件中找到了一样的类,则使用loadClass(String, ClassLoader)
加载这个类, 然后调用fixClass(String, ClassLoader)
修复这个类。
AndFixManager fixClass(Class<?>, ClassLoader)
private void fixClass(Class<?> clazz, ClassLoader classLoader) { //使用反射获取这个类中所有的方法Method[] methods = clazz.getDeclaredMethods();//MethodReplace是这个库自定义的Annotation,标记哪个方法需要被替换MethodReplace methodReplace;String clz;String meth;for (Method method : methods) { //找到被MethodReplace注解的方法methodReplace = method.getAnnotation(MethodReplace.class);if (methodReplace == null)continue;clz = methodReplace.clazz();meth = methodReplace.method();if (!isEmpty(clz) && !isEmpty(meth)) {replaceMethod(classLoader, clz, meth, method);}}}
在源码中基本把这个方法给解读完了,接下来就要看看它调用的replaceMethod(ClassLoader, String,String, Method)
方法
AndFixManager replaceMethod(ClassLoader, String,String, Method)
private void replaceMethod(ClassLoader classLoader, String clz,String meth, Method method) {//对每个类创建一个不会冲突的key String key = clz + "@" + classLoader.toString(); //mFixedClass是一个Map<String, Class<?>>,并被实例化为ConcurrentHashMap<>(); Class<?> clazz = mFixedClass.get(key); if (clazz == null) {// class not load Class<?> clzz = classLoader.loadClass(clz); // initialize target class and modify access flag of class’ fields to public clazz = AndFix.initTargetClass(clzz); } if (clazz != null) {// initialize class OK mFixedClass.put(key, clazz); //获取名为meth的方法 Method src = clazz.getDeclaredMethod(meth, method.getParameterTypes()); AndFix.addReplaceMethod(src, method); }}
这里源代码中的英文注释(作者注释)已经很清楚了,去看看调用的那个静态方法AndFix.addReplaceMethod(src, method);
AndFix addReplaceMethod(Method, Method)
public static void addReplaceMethod(Method src, Method dest) {replaceMethod(src, dest); initFields(dest.getDeclaringClass());}
replaceMethod是一个native方法,声明如下: private static native void replaceMethod(Method dest, Method src);
由于暂时我对JNI不是很熟悉,所以这里就不分析了。 看看另外一个方法initFields(Class<?>)
/** * modify access flag of class’ fields to public * * @param clazz * class */private static void initFields(Class<?> clazz) {Field[] srcFields = clazz.getDeclaredFields();for (Field srcField : srcFields) {Log.d(TAG, "modify " + clazz.getName() + "." + srcField.getName()+ " flag:");setFieldFlag(srcField);}}
这里英文注释也很清楚了,只是其中调用了setFieldFlag(srcField);
这个我们没见过的方法, 声明为private static native void setFieldFlag(Field field);
又是个JNI方法,暂时不进行分析。
到这里,对阿里AndFix库Java层面上的代码的分析就结束了,如果还想了解native层的代码,我将会放在下一篇,敬请等待。
原文地址:http://yunair.github.io/blog/2015/10/23/AndFix-%E8%A7%A3%E6%9E%90(%E4%B8%8B).html
- AndFix解析——(下)
- AndFix解析——(下)
- AndFix解析——(上)
- AndFix解析——(中)
- AndFix解析——(上)
- AndFix解析——(中)
- AndFix热修复 —— 实战与源码解析
- AndFix热修复 —— 实战与源码解析
- AndFix热修复 —— 实战与源码解析
- AndFix热修复 —— 实战与源码解析
- Android热修复学习之旅——Andfix框架完全解析
- Android热修复框架——AndFix
- Android热修复实践应用—AndFix
- Android热修复方案—AndFix
- AndFix原理以及源码解析
- Eclipse下Andfix的使用
- andfix
- AndFix
- 【u122】迎接仪式
- 高通平台添加自己的product后com.qualcomm.qti.tetherservice不停crash
- FMDB创建数据库的增删改查
- Dependency与DependencyManagement的区别
- portus + 私有registry 碰到的问题(解决auth问题)
- AndFix解析——(下)
- 学习python的第二十天
- {小结}NOIP2016提高组比赛分析
- java中Math.max()的方法使用.lang
- Spring实战(第4版) Spring Inaction 笔记(第五章)Spring MVC
- 【杭电】1000 A + B Problem
- Flask之处理客户端通过POST方法传送的数据
- Linux 中 rc.local、init.d、rc.x、init 这几个文件(夹)各有什么作用?启动执行的脚本应该均放在 rc.local 中吗?
- Android6.0 Bluetooth学习