Understand how the Android class loader works and the role of DexPathList in the class loading process

Understand how the Android class loader works and the role of DexPathList in the class loading process

Class Loader

In Android, the class loader is an important component responsible for dynamically loading the JVM and Android class libraries at runtime. Android's class loader system is based on the JVM's class loader model, but with some specific adjustments and optimizations to suit the needs of the Android platform.

(1) Bootstrap ClassLoader:

  • This is the top-level class loader, implemented by the JVM.
  • Mainly loads Java and Android core class libraries.
  • Typically pass null as the parent loader.

(2) PathClassLoader (or DexClassLoader):

  • Android-specific class loader, used to load classes from APK files, DEX files, or JAR/ZIP files.
  • PathClassLoader is the default class loader for Android applications, which is used to load application classes and resources.

DexClassLoader is a subclass of PathClassLoader, which provides the ability to load DEX files from a specified path, dynamically load plugins, or use loaders commonly used in modular scenarios.

 //DexClassLoader.java package dalvik.system; public class DexClassLoader extends BaseDexClassLoader { public DexClassLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent) { super(dexPath, new File(optimizedDirectory), libraryPath, parent); } public DexClassLoader(String dexPath, String optimizedDirectory, String librarySearchPath, ClassLoader parent) { super(dexPath, null, librarySearchPath, parent); } } //PathClassLoader package dalvik.system; 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); } }

It can be found that the source code of PathClassLoader and DexClassLoader is very simple, and only contains a constructor to call the parent class BaseDexClassLoader (all work should be done in BaseDexClassLoader). The difference between the two loaders is that the optimizedDirectory parameter is missing in the construction of PathClassLoader. The reason is that PathClassLoader loads the apk in /data/app, that is, the apk in the system, and this part of the apk will be decompressed and released to the specified directory. This operation is completed by the system and does not require a separate path to be passed in. The DexClassLoader is passed in to cache the dex file to be loaded and create a DexFile object. If it is null, the original path of the dex file will be used directly to create the DexFile (this parameter has been deprecated and is invalid since API26).

(3) System ClassLoader (or AppClassLoader):

  • The application class loader of the Android system is inherited from URLClassLoader.
  • Classes used to load Android system classes and applications.
  • In Android, System ClassLoader or AppClassLoader is not directly referenced, but obtained through ClassLoader.getSystemClassLoader().

(4) Custom ClassLoader:

  • You can inherit the ClassLoader class or its subclasses (such as DexClassLoader) to create a custom class loader.
  • Custom class loaders can be used to load classes over the network, load encrypted classes from a database, or implement more complex class loading logic.

The main uses of class loaders are:

  • Dynamically load and execute code, such as plug-in development, hot update, etc.
  • Load and execute code from different sources, such as JAR packages or DEX files downloaded from the network.
  • Isolate code from different sources to prevent class conflicts and security issues.

Note: Misusing class loaders can lead to memory leaks and performance issues. When using class loaders, you should carefully consider their lifecycle and resource management.

DexPathList

DexPathList is an internal class used by class loaders such as DexClassLoader and BaseDexClassLoader to process DEX file paths. DexPathList plays a key role when using DexClassLoader or BaseDexClassLoader to load DEX files.

(1) Function: DexPathList is responsible for managing and maintaining the path information of DEX files, so that the class loader can correctly find and load the classes in the DEX files.

(2) Construction: DexPathList is created in the constructor of DexClassLoader or BaseDexClassLoader. When constructing DexPathList, you need to provide parameters such as the path of the DEX file, the optimization directory, the library path, and the parent class loader.

 public class BaseDexClassLoader extends ClassLoader { private final DexPathList pathList; public BaseDexClassLoader(String dexPath, File optimizedDirectory, String librarySearchPath, ClassLoader parent) { super(parent); this.pathList = new DexPathList(this, dexPath, librarySearchPath, optimizedDirectory); } @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; } }

(3) Member variables: DexPathList has a private final member variable dexElements, which is an Element array that contains the Element objects of all DEX files. Each Element object corresponds to a DEX file.

 private final Element[] dexElements; public DexPathList(ClassLoader definingContext, String dexPath, String libraryPath, File optimizedDirectory) { ... this.definingContext = definingContext; this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,suppressedExceptions); ... }

(4) Loading DEX files: In the constructor of DexPathList, the makeDexElements() method is called to load DEX files. This method traverses the provided DEX file path list and creates an Element object for each DEX file, and then adds these Element objects to the dexElements array.

 private static Element[] makeDexElements(ArrayList<File> files, File optimizedDirectory, ArrayList<IOException> suppressedExceptions) { // 1.创建Element集合ArrayList<Element> elements = new ArrayList<Element>(); // 2.遍历所有dex文件(也可能是jar、apk或zip文件) for (File file : files) { ZipFile zip = null; DexFile dex = null; String name = file.getName(); ... // 如果是dex文件if (name.endsWith(DEX_SUFFIX)) { dex = loadDexFile(file, optimizedDirectory); // 如果是apk、jar、zip文件(这部分在不同的Android版本中,处理方式有细微差别) } else { zip = file; dex = loadDexFile(file, optimizedDirectory); } ... // 3.将dex文件或压缩文件包装成Element对象,并添加到Element集合中if ((zip != null) || (dex != null)) { elements.add(new Element(file, false, zip, dex)); } } // 4.将Element集合转成Element数组返回return elements.toArray(new Element[elements.size()]); }

(5) Loading a class: When the class loader needs to load a class, it does so through the loadClass() method of DexPathList. This method iterates through each Element object in the dexElements array and attempts to load the class from the corresponding DEX file. Once the class to be loaded is found, the Class object of the class is returned.

 public Class findClass(String name, List<Throwable> suppressed) { for (Element element : dexElements) { // 遍历出一个dex文件DexFile dex = element.dexFile; if (dex != null) { // 在dex文件中查找类名与name相同的类Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed); if (clazz != null) { return clazz; } } } if (dexElementsSuppressedExceptions != null) { suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions)); } return null; }

(6) Optimization: To improve performance, DexPathList also supports optimization of DEX files. When loading DEX files, you can optimize the DEX files to a specified directory to reduce memory usage and increase loading speed.

<<:  iOS 18 hidden feature, supports T9 dialing!

>>:  Principle Analysis | Principle and Use of HandlerThread in Android

Recommend

Android development: from modularization to componentization (Part 1)

In the Android SDK article, we talked about modul...

Wuhan tea sn post bar

Wuhan Tea Tasting Contact Information I strongly ...

Douyin live streaming marketing strategy for the maternal and infant industry

Douyin is a comprehensive platform for selling go...

Curious questions for the Year of the Snake! Explore the most "snake"

Review expert: Wang Lei, National Park and Nature...

Practical explanation of efficiently adding rounded corners effect on iOS

[[163500]] Rounded corners are a very common visu...

[Creative Cultivation Program] How to tame the "hot-tempered" lithium battery?

Lithium batteries can be said to be a major proje...

China App Rankings in Q2 2016: The unstoppable dark horse and the unbeatable leader!

The freshly released “2016 Q2 China App Rankings”...

I'm so tired because I'm poisoned!!

Audit expert: Yin Tielun Unlike the energetic &qu...

The most effective content marketing promotion skills and methods!

01. The History of Content Marketing The term con...

Restoring factory settings is not free from porn scandals

Security software developer Avast this week questi...

Pit and fissure sealing: Let your child's teeth resist "sugar-coated bullets"

After seeing this picture, you must be wondering,...