Android中的ClassLoader

一、ClassLoader的类型

java中的ClassLoader和Android中的ClassLoader并不完全相同,因为java的可执行文件为class文件,而Android的可执行文件为dex文件,他们所加载的文件不同,因而所使用的ClassLoader也不相同。

Android中的ClassLoader分为两种类型,分别如下:

  1. 系统类加载器:BootClassLoader、PathClassLoader、DexClassLoader。
  2. 自定义加载器,即继承自系统的类加载器。

1.1 BootClassLoader

Android系统启动时会使用BootClassLoader来预加载常用类,它由Java实现,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//路径:/libcore/ojluni/src/main/java/java/lang/ClassLoader.java
class BootClassLoader extends ClassLoader {

private static BootClassLoader instance;

@FindBugsSuppressWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED")
public static synchronized BootClassLoader getInstance() {
if (instance == null) {
instance = new BootClassLoader();
}
return instance;
}

......
}

BootClassLoader是ClassLoader的内部类,并继承自ClassLoader。由于BootClassLoader的权限声明是默认的,只有在同一包中才能访问,因此我们在应用程序中是无法直接调用的。

1.2 DexClassLoader

DexClassLoader是用来加载dex文件以及包含dex文件的压缩包(apk、jar)。它的代码如下:

1
2
3
4
5
6
7
//路径:/libcore/dalvik/src/main/java/dalvik/system/DexClassLoader.java
public class DexClassLoader extends BaseDexClassLoader {
public DexClassLoader(String dexPath, String optimizedDirectory,
String librarySearchPath, ClassLoader parent) {
super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);
}
}

参数解析如下:

  • dexPath:dex文件或包含dex文件的jar/apk文件的路径集合,多个路径用文件分隔符分隔,默认文件分隔符为”:”。
  • optimizedDirectory:dex优化后产生的文件所存放的路径。
  • librarySearchPath:native库的路径集合,多个路径用文件分隔符分隔。
  • parent:父加载器

DexClassLoader继承自BaseDexClassLoader,它的方法均在BaseDexClassLoader中实现。DexClassLoader通常用来加载已安装的jar、apk、dex以及SD卡中加载未安装的apk。

1.3 PathClassLoader

Android系统使用PathClassLoader来加载系统类和应用程序的类,它的代码如下:

1
2
3
4
5
6
7
8
9
10
11
//路径:/libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.java
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);
}
}

同DexClassLoader一样,PathClassLoader继承自BaseDexClassLoader,方法也都在父类中实现。

可以注意到,PathClassLoader的构造方法中都没有optimizedDirectory参数,这是因为PathClassLoader中默认optimizedDirectory的值为/data/dalvik-cache(是的,默认dex优化文件的存放目录),因此PathClassLoader是用来加载系统中已经安装过的apk的dex文件。

1.4 BaseDexClassLoader

1
2
3
4
5
6
7
8
9
//路径:/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
public class BaseDexClassLoader extends ClassLoader {
private final DexPathList pathList; //记录dex文件路径信息

public BaseDexClassLoader(String dexPath, File optimizedDirectory, String libraryPath, ClassLoader parent) {
super(parent);
this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
}
}

BaseDexClassLoader继承自ClassLoader,在构造方法中初始化了DexPathList对象,这个对象比较关键,后续会讲解到。

1.5 ClassLoader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//路径:/libcore/ojluni/src/main/java/java/lang/ClassLoader.java
public abstract class ClassLoader {
private ClassLoader parent; //记录父类加载器

private static Void checkCreateClassLoader() {
return null;
}

private ClassLoader(Void unused, ClassLoader parent) {
this.parent = parent;
}

protected ClassLoader() {
this(checkCreateClassLoader(), getSystemClassLoader());
}

protected ClassLoader(ClassLoader parent) {
this(checkCreateClassLoader(), parent);
}

}

ClassLoader是一个抽象类,在构造方法中调用了getSystemClassLoader()方法,获取SystemClassLoader,它的代码同样在ClassLoader类中,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public abstract class ClassLoader {

static private class SystemClassLoader {
public static ClassLoader loader = ClassLoader.createSystemClassLoader();
}
public static ClassLoader getSystemClassLoader() {
return SystemClassLoader.loader;
}
private static ClassLoader createSystemClassLoader() {
String classPath = System.getProperty("java.class.path", ".");
String librarySearchPath = System.getProperty("java.library.path", "");
return new PathClassLoader(classPath, librarySearchPath, BootClassLoader.getInstance());
}
}

可见SystemClassLoader对应的是PathClassLoader。

从ClassLoader的代码中可以看出,每创建一个ClassLoader实例,都需要一个现有的ClassLoader实例作为新创建的实例的Parent,这样一来,所有的ClassLoader之间的关联就像一棵树一样,这也是ClassLoader的 双亲代理模型的特点。

二、ClassLoader的继承关系

它们之间的继承关系如下图所示:

a.drawio

  • ClassLoader:它是一个抽象类,其中定义了ClassLoader的主要功能。
  • BootClassLoader:它是ClassLoader的内部类,并继承自ClassLoader,用来在Android系统启动时预加载常用类。
  • SecureClassLoader:它与JDK 8 中的SecureClassLoader类的代码是一样的,它继承自ClassLoader。SecureClassLoader扩展了ClassLoader类的权限方面的功能,加强了ClassLoader的安全性。
  • URLClassLoader:它与JDK 8 中的URLClassLoader类的代码是一样的,它继承自SecureClassLoader,用来通过URL路径从jar文件和文件夹中加载类和资源。
  • BaseDexClassLoader:它继承自ClassLoader,是抽象类ClassLoader的具体实现类。
  • InMemoryDexClassLoader:它是Android 8.0 新增的类加载器,继承自BaseDexClassLoader,用于加载内存中的dex文件。
  • PathClassLoader:它继承自BaseDexClassLoader,用来加载系统中已经安装过的apk的dex文件。
  • DexClassLoader:它继承自BaseDexClassLoader,用来加载已安装的jar、apk、dex以及SD卡中加载未安装的apk。

在实际开发过程中,我们一般是使用DexClassLoader和PathClassLoader这两个类加载器来加载类。

三、类加载器的双亲委托模式

类加载器查找Class所采用的是双亲委托模式,具体为:首先判断该Class是否已经加载,如果没有,则委托给父加载器进行查找而不是自己先去查找,这样依次递归,直到委托到最顶层的ClassLoader,如果最顶层的ClassLoader找到了该Class,就会直接返回,如果没找到,则交还给子加载器查找,依次递归,如果还没找到则最后会交还给自己去查找。

请注意,父类加载器和子类加载器之间并不是继承关系的,而是使用组合关系来调用父类加载器,即创建类加载器时传入的parent参数。

对应ClassLoader中的核心代码loadClass()如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//路径:/libcore/ojluni/src/main/java/java/lang/ClassLoader.java
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// 先检查是否已经加载过了该类
Class<?> 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) {
//父加载器处理失败,自己来找
c = findClass(name);
}
}
return c;
}

private Class<?> findBootstrapClassOrNull(String name)
{
return null;
}

这段代码就很好的诠释了双亲委托模式。

双亲委托模式优点:

  1. 避免重复加载。
  2. 更加安全。如果不使用双亲委托模式,就可以自定义一个String类来替代系统的String类,这显然会造成安全隐患。(两个类名一致且被同一类加载器加载的类,JVM才会认为它们是同一个类)

四、ClassLoader加载类的过程

ClassLoader加载类的方法为loadClass(),它被定义在抽象类ClassLoader中,具体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//路径:/libcore/ojluni/src/main/java/java/lang/ClassLoader.java
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// 先检查是否已经加载过了该类
Class<?> 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) {
//父加载器处理失败,自己来找
c = findClass(name);
}
}
return c;
}

private Class<?> findBootstrapClassOrNull(String name)
{
return null;
}

首先调用findLoadedClass()方法查看本身有没有加载过该类,对应代码如下:

1
2
3
4
5
6
7
8
9
//路径:/libcore/ojluni/src/main/java/java/lang/ClassLoader.java
protected final Class<?> findLoadedClass(String name) {
ClassLoader loader;
if (this == BootClassLoader.getInstance())
loader = null;
else
loader = this;
return VMClassLoader.findLoadedClass(loader, name);
}

继而调用VMClassLoader的findLoadedClass()方法,

1
2
//路径:/libcore/libart/src/main/java/java/lang/VMClassLoader.java
native static Class findLoadedClass(ClassLoader cl, String name);

这个方法需要在native层实现。

OK!回到loadClass()的流程中,之后是调用父加载器的loadClass()方法(如果存在父加载器),其实就是这个方法本身。

接下来看findClass()方法,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
//路径:/libcore/ojluni/src/main/java/java/lang/ClassLoader.java
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
return Class.classForName(name, false, null);
}
//路径:/libcore/ojluni/src/main/java/java/lang/Class.java
static native Class<?> classForName(String className, boolean shouldInitialize,
ClassLoader classLoader) throws ClassNotFoundException;

第一个findClass()方法直接抛异常,这说明需要子类来实现;第二个findClass()方法则调用的是Class类中的classForName()方法,是个native方法。

回到第一个findClass()方法,它的实现在BaseDexClassLoader类中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//路径:/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
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;
}

public BaseDexClassLoader(String dexPath, File optimizedDirectory, String librarySearchPath, ClassLoader parent) {
super(parent);
this.pathList = new DexPathList(this, dexPath, librarySearchPath, null);
if (reporter != null) {
reporter.report(this.pathList.getDexPaths());
}
}

public BaseDexClassLoader(ByteBuffer[] dexFiles, ClassLoader parent) {
super(parent);
this.pathList = new DexPathList(this, dexFiles);
}

在该方法中调用了pathList的findClass()方法,这个pathList实在BaseDexClassLoader实例初始化时创建的,是一个DexPathList对象,对应的findClass()方法代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//路径:/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
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;
}

遍历Element数组dexElements,并对每个元素调用其findClass()方法。

整个代码其实就是遍历加载过的所有dex文件,看它们里面是否存在需要加载的类。至于为什么是dex文件,详见文章dex文件加载流程(一)中的DexPathList的创建。

热修复核心逻辑:在DexPathList.findClass()过程,一个Classloader可以包含多个dex文件,每个dex文件被封装到一个Element对象,这些Element对象排列成有序的数组dexElements。当查找某个类时,会遍历所有的dex文件,如果找到则直接返回,不再继续遍历dexElements。也就是说当两个类不同的dex中出现,会优先处理排在前面的dex文件,这便是热修复的核心精髓,将需要修复的类所打包的dex文件插入到dexElements前面。 ——gityuan

OK!接下来就是查看Element类的findClass()方法,Element类是DexPathList类中的一个静态类,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
//路径:/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
static class Element {
private final DexFile dexFile;
......
public Class<?> findClass(String name, ClassLoader definingContext,
List<Throwable> suppressed) {
return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
: null;
}
......
}

findClass()方法中调用了DexFile的loadClassBinaryName()方法,具体代码如下:

1
2
3
4
//路径:/libcore/dalvik/src/main/java/dalvik/system/DexFile.java
public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) {
return defineClass(name, loader, mCookie, this, suppressed);
}

继而调用defineClass()方法,对应代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//路径:/libcore/dalvik/src/main/java/dalvik/system/DexFile.java
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;
}

private static native Class defineClassNative(String name, ClassLoader loader, Object cookie,
DexFile dexFile)
throws ClassNotFoundException, NoClassDefFoundError;

最终调用的是defineClassNative()方法来查找所需要加载的类,而这个方法是个native方法,这里就不再分析了。

这里借用huanzhiyazi的文章中的一句话来概括一下native层做的事:先从已加载类的 class_table 中查询,若找到则直接返回;若找不到则说明该类是第一次加载,则执行加载流程,其中可能需要穿插加载依赖的类,加载完成后将其缓存到 class_table 中。

五、预加载类的流程

在ZygoteInit的main()方法中,会调用preload()方法,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//路径:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
......

try {
......
// In some configurations, we avoid preloading resources and classes eagerly.
// In such cases, we will preload things prior to our first fork.
if (!enableLazyPreload) {
......
preload(bootTimingsTraceLog);
......
}
......
}
......
}

preload()代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//路径:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
static void preload(TimingsTraceLog bootTimingsTraceLog) {
Log.d(TAG, "begin preload");
bootTimingsTraceLog.traceBegin("BeginIcuCachePinning");
beginIcuCachePinning();
bootTimingsTraceLog.traceEnd(); // BeginIcuCachePinning
bootTimingsTraceLog.traceBegin("PreloadClasses");
preloadClasses();
bootTimingsTraceLog.traceEnd(); // PreloadClasses
bootTimingsTraceLog.traceBegin("PreloadResources");
preloadResources();
bootTimingsTraceLog.traceEnd(); // PreloadResources
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
nativePreloadAppProcessHALs();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");
preloadOpenGL();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
preloadSharedLibraries();
preloadTextResources();
// Ask the WebViewFactory to do any initialization that must run in the zygote process,
// for memory sharing purposes.
WebViewFactory.prepareWebViewInZygote();
endIcuCachePinning();
warmUpJcaProviders();
Log.d(TAG, "end preload");

sPreloadComplete = true;
}

preload()方法中,会预加载类、资源、共享库等等。其中preloadClasses()方法用于Zygote进程初始化时预加载常用类,该方法对应代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//路径:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
private static void preloadClasses() {
final VMRuntime runtime = VMRuntime.getRuntime();
InputStream is;
try {
//将/system/etc/preloaded-classes文件封装成FileInputStream
is = new FileInputStream(PRELOADED_CLASSES);
} catch (FileNotFoundException e) {
...
}
...
try {
//将FileInputStream封装成BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(is), 256);
int count = 0;
String line;
//读取预加载类记录
while ((line = br.readLine()) != null) {
// Skip comments and blank lines.
line = line.trim();
if (line.startsWith("#") || line.equals("")) {
continue;
}
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, line);
try {
if (false) {
Log.v(TAG, "Preloading " + line + "...");
}
//通过Class.forName()来加载和初始化给定的类
Class.forName(line, true, null);
count++;
} catch (ClassNotFoundException e) {
Log.w(TAG, "Class not found for preloading: " + line);
} catch (UnsatisfiedLinkError e) {
Log.w(TAG, "Problem preloading " + line + ": " + e);
} catch (Throwable t) {
...
}
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
}
...
} catch (IOException e) {
...
} finally {
...
}
}

常量PRELOADED_CLASSES的值为/system/etc/preloaded-classes,在preloaded-classes文件中存有预加载记录,这个文件在Android源码中的目录为/frameworks/base/preloaded-classes,这里举例一些文件中的预加载类:

1
2
3
4
5
6
7
8
9
10
11
12
13
android.app.ApplicationLoaders
android.app.ApplicationPackageManager
android.app.ContentProviderHolder
android.app.DexLoadReporter
android.app.Dialog
android.app.DownloadManager
android.app.Fragment
android.animation.Animator
android.app.Activity
android.app.ActivityManager
android.app.ActivityThread
java.lang.String
java.lang.Thread

很眼熟吧,不然怎么叫常见类呢!

回到preloadClasses()方法中,遍历预加载类记录,对每个预加载类调用Class.forName()方法,该方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//路径:/libcore/ojluni/src/main/java/java/lang/Class.java
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException
{
if (loader == null) {
loader = BootClassLoader.getInstance();//创建BootClassLoader实例
}
Class<?> result;
try {
result = classForName(name, initialize, loader);//调用native方法
} catch (ClassNotFoundException e) {
Throwable cause = e.getCause();
if (cause instanceof LinkageError) {
throw (LinkageError) cause;
}
throw e;
}
return result;
}

如果没有就通过BootClassLoader.getInstance()创建BootClassLoader实例,该方法代码如下:

1
2
3
4
5
6
7
//路径:/libcore/ojluni/src/main/java/java/lang/ClassLoader.java
public static synchronized BootClassLoader getInstance() {
if (instance == null) {
instance = new BootClassLoader();
}
return instance;
}

然后创建好的BootClassLoader实例作为参数传入classForName()方法中,该方法是native方法,代码如下

1
2
3
//路径:/libcore/ojluni/src/main/java/java/lang/Class.java
static native Class<?> classForName(String className, boolean shouldInitialize,
ClassLoader classLoader) throws ClassNotFoundException;

Java层到此为止,接下来是Native层,不在这里分析。

回顾整个预加载类的流程,我们可以知道,BootClassLoader是在Zygote进程的Zygote入口方法(main)中被创建的,并用来加载preloaded-classes文件中存放的与加载类。

六、PathClassLoader的创建

PathClassLoader的创建也得从Zygote进程开始说起,Zygote进程启动SystemServer进程是会调用ZygoteInit的startSystemServer()方法,具体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//路径:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer)
throws Zygote.MethodAndArgsCaller, RuntimeException {
...
int pid;
try {
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}

zygoteServer.closeServerSocket();
handleSystemServerProcess(parsedArgs);
}
return true;
}

Zygote通过forkSystemServer()方法fork自身来创建子进程(SystemServer进程),如果返回的pid=0,说明当前代码是在新创建的SystemServer进程中执行的,接着就会调用handleSystemServerProcess()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//路径:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) throws Zygote.MethodAndArgsCaller {
...
if (parsedArgs.invokeWith != null) {
...
} else {
ClassLoader cl = null;
if (systemServerClasspath != null) {
//创建PathClassLoader
cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
//设置成线程的上下文的类加载器
Thread.currentThread().setContextClassLoader(cl);
}
ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}
}

调用createPathClassLoader()方法创建PathClassLoader,然后获取当前线程实例,设置新创建的PathClassLoader为上下文的类加载器createPathClassLoader()方法如下:

1
2
3
4
5
6
7
8
9
static PathClassLoader createPathClassLoader(String classPath, int targetSdkVersion) {
String libraryPath = System.getProperty("java.library.path");
return PathClassLoaderFactory.createClassLoader(classPath,
libraryPath,
libraryPath,
ClassLoader.getSystemClassLoader(),
targetSdkVersion,
true /* isNamespaceShared */);
}

java.library.path 是一个系统属性,它指定了 Java 虚拟机 (JVM) 在加载本地库时应搜索的路径。上述代码通过System.getProperty("java.library.path")获取本地库信息,然后调用PathClassLoaderFactory类的createClassLoader()方法创建PathClassLoader。createClassLoader()方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//路径:/frameworks/base/core/java/com/android/internal/os/PathClassLoaderFactory.java
public static PathClassLoader createClassLoader(String dexPath,
String librarySearchPath,
String libraryPermittedPath,
ClassLoader parent,
int targetSdkVersion,
boolean isNamespaceShared) {
//创建PathClassLoader
PathClassLoader pathClassloader = new PathClassLoader(dexPath, librarySearchPath, parent);

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "createClassloaderNamespace");
String errorMessage = createClassloaderNamespace(pathClassloader,
targetSdkVersion,
librarySearchPath,
libraryPermittedPath,
isNamespaceShared);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

if (errorMessage != null) {
throw new UnsatisfiedLinkError("Unable to create namespace for the classloader " +
pathClassloader + ": " + errorMessage);
}

return pathClassloader;
}

上述代码直接通过new创建PathClassLoader实例。

回顾整个预加载类的流程,我们可以知道,PathClassLoader是在SystemServer进程中采用工厂模式创建的。


参考:

http://aospxref.com/android-8.0.0_r36/

https://github.com/huanzhiyazi/articles/issues/30

http://liuwangshu.cn/application/classloader/2-android-classloader.html

http://gityuan.com/2017/03/19/android-classloader/

Android动态加载基础 ClassLoader工作机制 - 中二病也要开发ANDROID - SegmentFault 思否

Android动态加载技术 简单易懂的介绍方式 - 中二病也要开发ANDROID - SegmentFault 思否

Android动态加载入门 简单加载模式 - 中二病也要开发ANDROID - SegmentFault 思否


Android中的ClassLoader
http://example.com/2023/11/25/Android安全/Android中的ClassLoader/
作者
gla2xy
发布于
2023年11月25日
许可协议