mLoaders = new ConcurrentHashMap
}
new了个AndFixmanager,看一下
public AndFixManager(Context context) { mContext = context; mSupport = Compat.*isSupport*(); if (mSupport) { mSecurityChecker = new SecurityChecker(mContext); mOptDir = new File(mContext.getFilesDir(), *DIR*); if (!mOptDir.exists() && !mOptDir.mkdirs()) {// make directory fail mSupport = false; Log.*e*(*TAG*, "opt dir create error."); } else if (!mOptDir.isDirectory()) {// not directory mOptDir.delete(); mSupport = false; } } }
在这个类里面主要是检测设备是否是支持的AndFix的设备,YunOS不支持。
在SecurityChecker里面获取数字证书和检测应用是否debugable
另外是初始化patch路径
PachManager.init()里面获取AndFix的版本信息,如果信息一致
public void init(String appVersion) { if (!mPatchDir.exists() && !mPatchDir.mkdirs()) {// make directory fail Log.*e*(*TAG*, "patch dir create error."); return; } else if (!mPatchDir.isDirectory()) {// not directory mPatchDir.delete(); return; } SharedPreferences sp = mContext.getSharedPreferences(*SP_NAME*, Context.*MODE_PRIVATE*); String ver = sp.getString(*SP_VERSION*, null); if (ver == null || !ver.equalsIgnoreCase(appVersion)) { cleanPatch(); sp.edit().putString(*SP_VERSION*, appVersion).commit(); } else { initPatchs(); } }
则initPatchs
private void initPatchs() { File[] files = mPatchDir.listFiles(); for (File file : files) { addPatch(file); } }
把路径下的patch加到mPatch列表里面。
patchManager.loadPatch();
public void loadPatch() { mLoaders.put("*", mContext.getClassLoader());// wildcard Set patchNames; List classes; for (Patch patch : mPatchs) { patchNames = patch.getPatchNames(); for (String patchName : patchNames) { classes = patch.getClasses(patchName); mAndFixManager.fix(patch.getFile(), mContext.getClassLoader(), classes); } } }
最终调用fix方法
mAndFixManager.fix(patch.getFile(), mContext.getClassLoader(), classes);
fix方法首先签名验证,一般是文件的MD5,通过之后获取dex文件,
然后实现自己的加载器(只需要继承ClassLoader,并覆盖findClass方法)。
ClassLoader patchClassLoader = new ClassLoader(classLoader) { @Override protected 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; } }; Enumeration 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); } } } catch (IOException e) { Log.e(*TAG*, "pacth", e); }
在类加载器里面,如果知道需要修改的方法(annotation标记的),则调用fixClass去修复bug.
private void fixClass(Class> clazz, ClassLoader classLoader) { Method[] methods = clazz.getDeclaredMethods(); MethodReplace methodReplace; String clz; String meth; for (Method method : methods) { 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); } } }
在fixClass里面调用replaceMethod方法用patch里面的方法替换掉要修改的方法。
private void replaceMethod(ClassLoader classLoader, String clz, String meth, Method method) { try { String key = clz + "@" + classLoader.toString(); Class> clazz = *mFixedClass*.get(key); if (clazz == null) {// class not load Class> clzz = classLoader.loadClass(clz); // initialize target class clazz = AndFix.*initTargetClass*(clzz); } if (clazz != null) {// initialize class OK *mFixedClass*.put(key, clazz); Method src = clazz.getDeclaredMethod(meth, method.getParameterTypes()); AndFix.*addReplaceMethod*(src, method); } } catch (Exception e) { Log.e(*TAG*, "replaceMethod", e); } }
最终调用native层的方法
AndFix.*addReplaceMethod*(src, method);
public static void addReplaceMethod(Method src, Method dest) { try {