Android类加载流程

背景由于前前前阵子写了个壳 , 得去了解类的加载流程 , 当时记了一些潦草的笔记 。这几天把这些东西简单梳理了一下 , 本文分析的代码基于Android8.1.0源码 。
流程分析从loadClass开始 , 我们来看下Android中类加载的流程

/libcore/ojluni/src/main/java/java/lang/ClassLoader.java::loadClass
loadClass流程如下:
Android类加载流程

文章插图
protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{// First, check if the class has already been loadedClass<?> c = findLoadedClass(name);if (c == null) {try {if (parent != null) {c = parent.loadClass(name, false);} else {c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {// ClassNotFoundException thrown if class not found// from the non-null parent class loader}if (c == null) {// If still not found, then invoke findClass in order// to find the class.c = findClass(name);}}return c;}
/libcore/ojluni/src/main/java/java/lang/ClassLoader.java::findClass
protected Class<?> findClass(String name) throws ClassNotFoundException {throw new ClassNotFoundException(name);}ClassLoader类的findClass是没有实际查找代码的 , 所以调用findClass其实是调用其实现类的findClass函数 , 例如:BaseDexClassLoader
/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java::findClass
每个BaseDexClassLoader都持有一个DexPathList , BaseDexClassLoader的findClass类调用了DexPathList的findClass 。
@Overrideprotected 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/DexPathList.java::findClass
遍历所有dexElements , 并调用Element类的findClass 。
public Class<?> findClass(String name, List<Throwable> suppressed) {for (Element element : dexElements) {Class<?> clazz = element.findClass(name, definingContext, suppressed);if (clazz != null) {return clazz;}}if (dexElementsSuppressedExceptions != null) {suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));}return null;}题外话 , dexElements对象其实是DexPathList$Element类的数组 , 用于存储已加载的dex或者jar的信息 。
/libcore/dalvik/src/main/java/dalvik/system/DexPathList$Element::findClass
Element的findClass , 又去调用DexFile类的loadClassBinaryName , 可以理解为在单独的dex或者jar对象中加载类
public Class<?> findClass(String name, ClassLoader definingContext,List<Throwable> suppressed) {return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed): null;}
libcore\dalvik\src\main\java\dalvik\system\DexFile.java::loadClassBinaryName
去调用defineClass函数
public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) {return defineClass(name, loader, mCookie, this, suppressed);}
libcore\dalvik\src\main\java\dalvik\system\DexFile.java::defineClass
调用defineClassNative , 准备进入Native层
private static Class defineClass(String name, ClassLoader loader, Object cookie,DexFile dexFile, List<Throwable> suppressed) {Class result = null;try {result = defineClassNative(name, loader, cookie, dexFile);} catch (NoClassDefFoundError e) {if (suppressed != null) {suppressed.add(e);}} catch (ClassNotFoundException e) {if (suppressed != null) {suppressed.add(e);}}return result;}

经验总结扩展阅读