public class HotFix {
final static String TAG = "HotFix";
public static void hotFixDex(ClassLoader loader, List<File> additionalDexes,
File optimizedDirectory) {
try {
V19.hotFixDex(loader, additionalDexes, optimizedDirectory);
} catch (Exception e) {
e.printStackTrace();
}
}
private static final class V19 {
private static void hotFixDex(ClassLoader loader, List<File> additionalClassPathEntries,
File optimizedDirectory) {
* 通过反射修改它的pathList(DexPathList)属性,来添加额外的dex文件入口;
*/
Field pathListField = findField(loader, "pathList");
Object dexPathList = pathListField.get(loader);
ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>();
Object[] elements = makeDexElements(dexPathList,
new ArrayList<File>(additionalClassPathEntries), optimizedDirectory,
suppressedExceptions);
printElementDir(elements);
expandFieldArray(dexPathList, "dexElements", elements);
}
* A wrapper around
* {@code private static final dalvik.system.DexPathList#makeDexElements}.
*/
private static Object[] makeDexElements(Object dexPathList,
ArrayList<File> files, File optimizedDirectory,
ArrayList<IOException> suppressedExceptions) {
Method makeDexElements = findMethod(dexPathList,
"makePathElements", List.class, File.class, List.class);
makeDexElements.setAccessible(true);
return (Object[]) makeDexElements.invoke(null, files, optimizedDirectory,
suppressedExceptions);
}
private static void printElementDir(Object[] elements) {
for (int i = 0; i < elements.length; i++) {
try {
Field f = findField(elements[i], "dir");
f.setAccessible(true);
File file = (File) f.get(elements[i]);
Log.e(TAG, "dir = " + file.getAbsolutePath());
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
private static Field findField(Object instance, String name) {
for (Class<?> clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
try {
Field field = clazz.getDeclaredField(name);
if (!field.isAccessible()) {
field.setAccessible(true);
}
return field;
} catch (NoSuchFieldException e) {
}
}
throw new NoSuchFieldException("Field " + name + " not found in " + instance.getClass());
}
private static Method findMethod(Object instance, String name, Class<?>... parameterTypes)
throws NoSuchMethodException {
for (Class<?> clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
try {
Method method = clazz.getDeclaredMethod(name, parameterTypes);
method.setAccessible(true);
return method;
} catch (NoSuchMethodException e) {
}
}
throw new NoSuchMethodException("Method " + name + " with parameters " +
Arrays.asList(parameterTypes) + " not found in " + instance.getClass());
}
private static void expandFieldArray(Object instance, String fieldName,
Object[] extraElements) {
Field jlrField = findField(instance, fieldName);
Object[] original = (Object[]) jlrField.get(instance);
Object[] combined = (Object[]) Array.newInstance(
original.getClass().getComponentType(), original.length + extraElements.length);
System.arraycopy(original, 0, combined, 0, original.length);
System.arraycopy(extraElements, 0, combined, original.length, extraElements.length);
jlrField.set(instance, combined);
}
}