文章目录
前言
一、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; } } }