文章目录
- 前言
- 一、DexPathList 构造函数分析
- 二、DexPathList.makeDexElements 函数分析
- 三、Element 类分析
前言
上一篇博客 【Android 逆向】整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | 类加载器构造函数分析 | DexPathList 引入 ) 中 , 分析了 DexClassLoader 构造函数的调用流程 , 在构造函数中执行的核心操作就是 在 BaseDexClassLoader 的构造函数中 初始化了 DexPathList 实例对象 ;
本篇博客中重点分析 DexPathList
;
一、DexPathList 构造函数分析
在 DexPathList 构造函数中 , 主要是调用了 makeDexElements()
方法 , 该方法返回 Element[]
数组元素 , 赋值给 private final Element[] dexElements
成员 ;
/*package*/ final class DexPathList {
/**
* List of dex/resource (class path) elements.
* Should be called pathElements, but the Facebook app uses reflection
* to modify 'dexElements' (http://b/7726934).
*/
private final Element[] dexElements;
/**
* Constructs an instance.
*
* @param definingContext the context in which any as-yet unresolved
* classes should be defined
* @param dexPath list of dex/resource path elements, separated by
* {@code File.pathSeparator}
* @param libraryPath list of native library directory path elements,
* separated by {@code File.pathSeparator}
* @param optimizedDirectory directory where optimized {@code .dex} files
* should be found and written to, or {@code null} to use the default
* system directory for same
*/
public DexPathList(ClassLoader definingContext, String dexPath,
String libraryPath, File optimizedDirectory) {
// 下面的代码 主要是对 参数合法性判断
if (definingContext == null) {
throw new NullPointerException("definingContext == null");
}
if (dexPath == null) {
throw new NullPointerException("dexPath == null");
}
if (optimizedDirectory != null) {
if (!optimizedDirectory.exists()) {
throw new IllegalArgumentException(
"optimizedDirectory doesn't exist: "
optimizedDirectory);
}
if (!(optimizedDirectory.canRead()
&& optimizedDirectory.canWrite())) {
throw new IllegalArgumentException(
"optimizedDirectory not readable/writable: "
optimizedDirectory);
}
}
// 上述代码是对参数合法性判断
this.definingContext = definingContext;
ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>();
// 核心逻辑
// 调用 makeDexElements 方法 , 传入
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions);
if (suppressedExceptions.size() > 0) {
this.dexElementsSuppressedExceptions =
suppressedExceptions.toArray(new IOException[suppressedExceptions.size()]);
} else {
dexElementsSuppressedExceptions = null;
}
this.nativeLibraryDirectories = splitLibraryPath(libraryPath);
}
}
源码路径 : /libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
二、DexPathList.makeDexElements 函数分析
DexPathList.makeDexElements 函数中 , 主要返回了一个 Element[]
数组 ; Element
是 DexPathList
的内部类 ;
/*package*/ final class DexPathList {
/**
* Makes an array of dex/resource path elements, one per element of
* the given array.
*/
private static Element[] makeDexElements(ArrayList<File> files, File optimizedDirectory,
ArrayList<IOException> suppressedExceptions) {
// 创建要返回的 Element 数组对应的集合
ArrayList<Element> elements = new ArrayList<Element>();
/*
* 打开并加载 dex 文件
* up front.
*/
for (File file : files) {
File zip = null;
DexFile dex = null;
String name = file.getName();
if (name.endsWith(DEX_SUFFIX)) { // .dex 后缀
// dex 后缀是 .dex , 进入该分支
// Raw dex file (not inside a zip/jar).
try {
// 从文件中加载 dex
dex = loadDexFile(file, optimizedDirectory);
} catch (IOException ex) {
System.logE("Unable to load dex file: " file, ex);
}
} else if (name.endsWith(APK_SUFFIX) || name.endsWith(JAR_SUFFIX)
|| name.endsWith(ZIP_SUFFIX)) {
// .apk , .jar , .zip 后缀 , 命中该分支
zip = file;
try {
dex = loadDexFile(file, optimizedDirectory);
} catch (IOException suppressed) {
/*
* 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).
* Let dex == null and hang on to the exception to add to the tea-leaves for
* when findClass returns null.
*/
suppressedExceptions.add(suppressed);
}
} else if (file.isDirectory()) {
// We support directories for looking up resources.
// This is only useful for running libcore tests.
elements.add(new Element(file, true, null, null));
} else {
System.logW("Unknown file type for: " file);
}
if ((zip != null) || (dex != null)) {
// 调用完毕后 , 如果获取的 DexFile 不为空 , 创建 Element 对象 , 并加入到 ArrayList 集合中
elements.add(new Element(file, false, zip, dex));
}
}
return elements.toArray(new Element[elements.size()]);
}
}
源码路径 : /libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
三、Element 类分析
Element 类是 DexPathList 的内部类 , 其第一个成员变量就是 private final File file
, 这个就是 dex 文件类 ;
/*package*/ final class DexPathList {
/**
* Element of the dex/resource file path
*/
/*package*/ static class Element {
private final File file;
private final boolean isDirectory;
private final File zip;
private final DexFile dexFile;
private ZipFile zipFile;
private boolean initialized;
public Element(File file, boolean isDirectory, File zip, DexFile dexFile) {
this.file = file;
this.isDirectory = isDirectory;
this.zip = zip;
this.dexFile = dexFile;
}
}
}