Load classes(反射创建加载.so文件)
2017-07-28 本文已影响72人
乐之飞于
Android类由DexClassLoader加载
public class DexClassLoader extends BaseDexClassLoader {
public DexClassLoader(String dexPath, String optimizedDirectory,
String libraryPath, ClassLoader parent) {
super(dexPath, new File(optimizedDirectory), libraryPath, parent);
}
}
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
String libraryPath, ClassLoader parent) {
super(parent);
this.originalPath = dexPath;
this.pathList =
new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
}
追踪下参数 dexPath,这个鬼通常是"/data/../*.apk",现用作创建pathList
public DexPathList(ClassLoader definingContext, String dexPath,
String libraryPath, File optimizedDirectory) {
...
this.dexElements =
makeDexElements(splitDexPath(dexPath), optimizedDirectory);
...
}
再创建dexElements,注意下面代码里的 Archive File Loading Block,压缩包加载代码块
private static final String DEX\_SUFFIX = ".dex";
private static final String JAR\_SUFFIX = ".jar";
private static final String ZIP\_SUFFIX = ".zip";
private static final String APK\_SUFFIX = ".apk";
...
private static Element[] makeDexElements(ArrayList\<File\> files,
File optimizedDirectory) {
ArrayList\<Element\> elements = new ArrayList\<Element\>();
/\*
\* Open all files and load the (direct or contained) dex files
\* up front.
\*/
for (File file : files) {
ZipFile zip = null;
DexFile dex = null;
String name = file.getName();
if (name.endsWith(DEX\_SUFFIX)) {
// Raw dex file (not inside a zip/jar).
...
} else if (name.endsWith(APK\_SUFFIX) || name.endsWith(JAR\_SUFFIX)
|| name.endsWith(ZIP\_SUFFIX)) {
//---------------------------------------------------
// Archive File Loading Block
// if (name.endsWith(".so") doFollowingWithReflect();
//---------------------------------------------------
try {
zip = new ZipFile(file);
} catch (IOException ex) {
/\*
\* Note: ZipException (a subclass of IOException)
\* might get thrown by the ZipFile constructor
\* (e.g. if the file isn't actually a zip/jar
\* file).
\*/
System.logE("Unable to open zip file: " + file, ex);
}
try {
dex = loadDexFile(file, optimizedDirectory);
} catch (IOException ignored) {
/\*
\* IOException might get thrown "legitimately" by
\* the DexFile constructor if the zip file turns
\* out to be resource-only (that is, no
\* classes.dex file in it). Safe to just ignore
\* the exception here, and let dex == null.
\*/
}
} else {
System.logW("Unknown file type for: " + file);
}
if ((zip != null) || (dex != null)) {
elements.add(new Element(file, zip, dex));
}
}
return elements.toArray(new Element[elements.size()]);
}
可以看到,DexClassLoader不支持".so"后缀
为了让应用启动时能自动复制插件包到应用存储目录,需要支持".so"后缀。做法就是模拟 压缩包加载代码块,创建一个dex元素,再反射添加到宿主class loader里的dexPathList。
伪代码:
Context context = getApplicationContext();
File plugin = new File(context.getApplicationInfo().dataDir, "lib/\*\*.so");
Element element = makeDexElement(plugin); // dalvik.system.DexPathList$Element
context.getClassLoader() // dalvik.system.DexClassLoader
.@dexPathList // dalvik.system.DexPathList
.@dexElements // dalvik.system.DexPathList$Element []
.insert(element, 0);