package com.antfortune.freeline.util;
import android.os.Build.VERSION;
import android.util.Log;
import dalvik.system.DexClassLoader;
import dalvik.system.DexFile;
import dalvik.system.PathClassLoader;
import java.io.File;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
public class DexUtils {
private static final String TAG = "Freeline.hackDex";
public static boolean inject(PathClassLoader classLoader, File dex, File opt) {
Log.i(TAG, dex.getAbsolutePath() + " dex length: " + dex.length());
Log.i(TAG, opt.getAbsolutePath() + " opt length: " + opt.length());
DexFile[] dexFiles = null;
Field pathListField = null;
Field fDexElements = null;
Object dstObject = null;
try {
Object newDexElements;
int dexLength;
if (VERSION.SDK_INT >= 14) {
pathListField = ReflectUtil.fieldGetOrg(classLoader, Class.forName("dalvik.system.BaseDexClassLoader"), "pathList");
fDexElements = ReflectUtil.fieldGetOrg(pathListField.get(classLoader), "dexElements");
Object e = fDexElements.get(pathListField.get(classLoader));
dstObject = e;
dexFiles = new DexFile[Array.getLength(e)];
for (int i = 0; i < Array.getLength(e); ++i) {
newDexElements = Array.get(e, i);
dexFiles[i] = (DexFile) ReflectUtil.fieldGet(newDexElements, "dexFile");
}
} else {
pathListField = ReflectUtil.fieldGetOrg(classLoader, "mDexs");
dstObject = pathListField.get(classLoader);
dexFiles = new DexFile[Array.getLength(dstObject)];
for (dexLength = 0; dexLength < Array.getLength(dstObject); ++dexLength) {
dexFiles[dexLength] = (DexFile) Array.get(dstObject, dexLength);
}
}
dexLength = Array.getLength(dstObject) + 1;
newDexElements = Array.newInstance(fDexElements.getType().getComponentType(), dexLength);
DexClassLoader dynamicDex = new DexClassLoader(dex.getAbsolutePath(), opt.getAbsolutePath(), null, classLoader.getParent());
Log.i(TAG, "after opt, dex len:" + dex.length() + "; opt len:" + opt.length());
Object pathList = pathListField.get(dynamicDex);
Object dexElements = fDexElements.get(pathList);
Object firstDexElement = Array.get(dexElements, 0);
Array.set(newDexElements, 0, firstDexElement);
for (int i = 0; i < dexLength - 1; ++i) {
Object element = Array.get(dstObject, i);
Array.set(newDexElements, i + 1, element);
}
if (VERSION.SDK_INT >= 14) {
fDexElements.set(pathListField.get(classLoader), newDexElements);
} else {
pathListField.set(classLoader, newDexElements);
}
return true;
} catch (Exception e) {
Log.e(TAG, "fail to override classloader " + classLoader + " with " + dex.getAbsolutePath(), e);
return false;
}
}
}