热修复
两种loader load不同的dex
首先需要将修复的class打包成dex(需要用dex工具)
SystemClassLoader:dexElements(classes1.dex,classes2.dex.......)
DexClassesLoader:dexElements(fixclasses.dex,)
然后利用反射拿到SystemClassLoader.pathList这个字段,然后再拿到dexElemens,和DexClassLoader中的Dex数组进行合并,最后再setField回SystemClassLoader中
方法类
public class HookHelper {
public static Object getField(Object object, Class<?> c1, String field) {
try {
Field localField = c1.getDeclaredField(field);
localField.setAccessible(true);
return localField.get(object);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void setField(Object object, Object value) {
try {
Field localField = object.getClass().getDeclaredField(value.getClass().getName());
localField.setAccessible(true);
localField.set(object, value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用
public class HotFix {
private static final String BASE_DEX_CLASS_LOADER = "dalvik.system.BaseDexClassLoader";
private static final String PATH_LIST = "pathList";
private static final String DEX_PATH_LIST = "dalvik.system.DexPathList";
private static final String ELEMENT_LIST = "dexElements";
//Dex插桩
private static void doDexInject(Context context, File fileDir, HashSet<File> loadedDEx) {
String optimizeDir = fileDir.getAbsolutePath() + File.separator + "opt_dex";
File fopt = new File(optimizeDir);
if (!fopt.exists()) {
fopt.mkdirs();
}
PathClassLoader pathClassLoader = (PathClassLoader) context.getClassLoader();
for (File file : loadedDEx) {
DexClassLoader classLoader = new DexClassLoader(file.getAbsolutePath(), optimizeDir, null, pathClassLoader);
//拿到ClassLoader-->PathList-->Elements
try {
//获取PathList
Object dexObj = HookHelper.getField(classLoader, Class.forName(BASE_DEX_CLASS_LOADER), PATH_LIST);
Object pathObj = HookHelper.getField(pathClassLoader, Class.forName(BASE_DEX_CLASS_LOADER), PATH_LIST);
//获取elements
Object dexDexElementList = HookHelper.getField(dexObj, Class.forName(DEX_PATH_LIST), ELEMENT_LIST);
Object pathDexElementList = HookHelper.getField(pathObj, Class.forName(DEX_PATH_LIST), ELEMENT_LIST);
//合并
Object allElements = combineArray(dexDexElementList, pathDexElementList);
//设置回去
HookHelper.setField(pathObj, allElements);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
//合并Element,修复包在前
private static Object combineArray(Object arrayLhs, Object arrayRhs) {
Class<?> localClass = arrayLhs.getClass().getComponentType();
int i = Array.getLength(arrayLhs);
int j = i + Array.getLength(arrayRhs);
Object result = Array.newInstance(localClass, j);
for (int k = 0; k < j; ++k) {
if (k < i) {
Array.set(result, k, Array.get(arrayLhs, k)); //修复包
} else {
Array.set(result, k, Array.get(arrayRhs, k - i)); //宿主
}
}
return result;
}
}