文章目录
一、分析 PathClassLoader 源码
二、分析 BaseDexClassLoader 源码
三、分析 PathDexList 源码
四、 源码资源
一、分析 PathClassLoader 源码
PathClassLoader 是 Android 平台的类加载器 , 继承了 BaseDexClassLoader ;
public class PathClassLoader extends BaseDexClassLoader { public PathClassLoader(String dexPath, ClassLoader parent) { super(dexPath, null, null, parent); } public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) { super(dexPath, null, librarySearchPath, parent); } }
源码路径 : libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.java
二、分析 BaseDexClassLoader 源码
BaseDexClassLoader 中的 findClass 方法 , 就是查找字节码类的核心方法 ;
BaseDexClassLoader 的 protected Class<?> findClass(String name) 是 protected 属性的 , 不能直接调用 , 需要通过反射才能调用 ;
应用调用所有的类的入口 , 就是该函数 , 所有 Java 类都是通过该类进行查找的 ;
BaseDexClassLoader 中的 findClass 方法分析 : 传入查找的类名 name 后 , 会调用 DexPathList pathList 成员的额 findClass 方法 ;
public class BaseDexClassLoader extends ClassLoader { /** * Hook for customizing how dex files loads are reported. * * This enables the framework to monitor the use of dex files. The * goal is to simplify the mechanism for optimizing foreign dex files and * enable further optimizations of secondary dex files. * * The reporting happens only when new instances of BaseDexClassLoader * are constructed and will be active only after this field is set with * {@link BaseDexClassLoader#setReporter}. */ /* @NonNull */ private static volatile Reporter reporter = null; private final DexPathList pathList; public BaseDexClassLoader(ByteBuffer[] dexFiles, ClassLoader parent) { // TODO We should support giving this a library search path maybe. super(parent); this.pathList = new DexPathList(this, dexFiles); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { List<Throwable> suppressedExceptions = new ArrayList<Throwable>(); Class c = pathList.findClass(name, suppressedExceptions); if (c == null) { ClassNotFoundException cnfe = new ClassNotFoundException( "Didn't find class \"" + name + "\" on path: " + pathList); for (Throwable t : suppressedExceptions) { cnfe.addSuppressed(t); } throw cnfe; } return c; } }
源码路径 : libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
三、分析 PathDexList 源码
应用调用类 A.java 时 , 通过 PathClassLoader 调用 , PathClassLoader 没有实际内容 , 只是继承 BaseDexClassLoader , 主要靠 BaseDexClassLoader 的 findClass 方法查找 A.class 文件 , BaseDexClassLoader 又调用 DexPathList pathList 成员的 findClass 方法 , 查找 A.class 文件 ;
当应用运行时调用到某类 A.class 时 , 会通过 PathClassLoader 加载该类 , PathClassLoader 是一个包装类 , 其中封装了 PathDexList 类 , 该类中的 Element[] dexElements 成员存放着多个 Dex 文件 ;
每个 Dex 文件中封装了多个 Class 字节码文件 ; 查找某个具体的 A.class 时 , 主要是通过 DexPathList 的 findClass 方法 , 遍历 Element[] dexElements 成员 ,
Element[] dexElements 数组中保存的就是内存中的 DEX 文件 , 如果 APP 中有 3 33 个 DEX 文件 , 那么该数组就有 3 33 个元素 ;
然后逐个遍历 获取该 element 中的 dexFile , 这是 DexFile 类型文件 ,
调用 DexFile 的 loadClassBinaryName 加载对应的 A.class 类 , 如果找到了 A.class 类 , 直接返回 ; 如果没有找到 , 则继续遍历下一个 Element[] dexElements 元素 ;
/*package*/ final class DexPathList { /** * dex/resource (class path) 元素集合. * 应该调用 pathElements , 但是 Facebook 应用通过反射修改 dexElements . */ private final Element[] dexElements; public Class findClass(String name, List<Throwable> suppressed) { for (Element element : dexElements) { DexFile dex = element.dexFile; if (dex != null) { Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed); // 注意 : 这里如果查找到想要的类 , 直接返回 , 不会去向后遍历 if (clazz != null) { return clazz; } } } if (dexElementsSuppressedExceptions != null) { suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions)); } return null; } }
参考源码地址 : libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
四、 源码资源
源码资源 :
GitHub 地址 : https://github.com/han1202012/HotFix
CSDN 源码快照 : https://download.csdn.net/download/han1202012/16651312