我们知道Dalvik(DVM)和ART加载的是dex文件,而JVM加载的是Class文件,因此Android和Java的类加载器ClassLoader是有去别的,因此本文分别介绍Java中的ClassLoader和Android中的ClassLoader。本文是基于JDK8 和 Android 8.1.0系统来分析 ClassLoader。
Java中的类加载器主要有两种类型,分别是系统类加载器和自定义类加载器。其中系统类加载器包括3中,分别是 Bootstrap ClassLoader、Extensions ClassLoader和Application ClassLoader。
1. Bootstrap ClassLoader(引导类加载器)
C/C++ 代码实现的加载器,用于加载指定的 JDK 的核心类库,比如 java.lang.、 java.uti. 等这些系统类。它用来加载以下目录中的类库:
1)$JAVA_HOME/jre/bin 目录。
2)-Xbootclasspath 参数指定的目录。
Java虚拟机的启动就是通过 Bootstrap ClassLoader 创建一个初始类来完成的。由于 Bootstrap ClassLoader 是使用C/C++ 实现的,所以该加载器不能被 Java 代码访问到。 Bootstrap ClassLoader 并不继承 Java.lang.ClassLoader 。我们可以通过如下代码来得出 Bootstrap ClassLoader 所加载的目录:
public class ClassLoaderTest {
public static void main(String[] args) {
String class_loader_path = System.getProperty("sun.boot.class.path");
System.out.println(class_loader_path);
}
}
打印结果如下:
D:\Program Files\Java\jre1.8.0_131\lib\resources.jar;
D:\Program Files\Java\jre1.8.0_131\lib\rt.jar;
D:\Program Files\Java\jre1.8.0_131\lib\sunrsasign.jar;
D:\Program Files\Java\jre1.8.0_131\lib\jsse.jar;
D:\Program Files\Java\jre1.8.0_131\lib\jce.jar;
D:\Program Files\Java\jre1.8.0_131\lib\charsets.jar;
D:\Program Files\Java\jre1.8.0_131\lib\jfr.jar;
D:\Program Files\Java\jre1.8.0_131\classes
2. Extensions ClassLoader(拓展类加载器)
Java 中的实现类为 ExtClassLoader ,因此可以简称为 ExtClassLoader ,它用于加载 Java 的拓展类,提供除了系统类之外的额外功能 。ExtClassLoader 用来加载以下目录中的类库:
1)加载 $JAVA_HOME/jre/lib/ext 目录。
2)系统属性 java.ext.dir 所指定的目录。
可以通过以下代码来得到Extensions ClassLoader 加载的目录:
public class ClassLoaderTest {
public static void main(String[] args) {
String class_loader_path = System.getProperty("java.ext.dirs");
System.out.println(class_loader_path);
}
}
打印结果如下:
D:\Program Files\Java\jre1.8.0_131\lib\ext;
C:\windows\Sun\Java\lib\ext
3. Application ClassLoader (应用程序类加载器)
除了系统提供的类加载器, 还可以自定义类加载器,自定义类加载器通过继承 java.lang.ClassLoader 类的方式来实现自己的类加载器, ExtClassLoader、 AppClassLoader 也继承了 Java.lang.ClassLoader 类。关于自定义类加载器后面会进行介绍。
当我们运行一个Java程序的时候会用到几种类型的类加载器呢?首先我们来看如下代码:
public class ClassLoaderTest {
public static void main(String[] args) {
ClassLoader loader = ClassLoaderTest.class.getClassLoader(); // ... 1
while(loader!= null) {
System.out.println("loader = " + loader); // ... 2
loader = loader.getParent();
}
}
}
在注释1处得到当前类ClassLoaderTest 的类加载器,并在注释2处打印出来,紧接着打印出当前类的类加载器的父类加载器,直到没有父类加载器实就终止循环,打印结果如下:
loader = sun.misc.Launcher$AppClassLoader@2a139a55
loader = sun.misc.Launcher$ExtClassLoader@7852e922
可以看到图1中共有5个ClassLoader相关类,下面简单对它们进行介绍。
1)ClassLoader 是一个抽象类,其中定义了ClassLoader的主要功能。
2)SecureClassLoader 继承了抽象类ClassLoader,但是SecureClassLoader 并不是 ClassLoader的实现类,而是拓展了ClassLoader 类,加入了权限方面的功能,加强了ClassLoader的安全性。
3)URLClassLoader 继承自 SecureClassLoader ,可以通过URL路径从jar文件和文件夹中加载类和资源。
4)ExtClassLoader 和 AppClassLoader 都继承自URLClassLoader,它们都是Launcher 的内部类,Launcher 是 Java 虚拟机的入口应用,ExtClassLoader 和 AppClassLoader 都是在Launcher中进行初始化的。
类加载器查找 Class 所采用的是双亲委托模式,所谓双亲委托模式就是首先判断该Class 是否已经加载,如果没有则不是自身去查找而是委托给父加载器进行查找,这样依次进行递归,直到委托到最顶层的 Bootstrap ClassLoader ,如果 Bootstrap ClassLoader 找到了 Class ,就会直接返回,如果没找到,则继续依次向下查找,如果还没找到则最后会交由自身去查找。如图2所示:
类加载子系统用来查找和加载 Class 文件到 Java 虚拟机中,假设我们要加载一个位于D盘的 Class 文件,这时系统所提供的类加载器不能满足条件,这时就需要自定义类加载器继承自 java.lang.ClassLoader 并复写它的 findClass 方法。 加载D盘的 Class 文件步骤如下:
1)自定义类加载器先从缓存中查找 Class 文件是否已经加载,如果已经加载就返回该 Class ,如果没加载则委托给父加载器也就是 AppClassLoader 。
2)按照图2中虚线的方向递归步骤1。
3)一直委托到 Bootstrap ClassLoader,如果 Bootstrap ClassLoader 查找缓存也没有加载 Class 文件,则在$JAVA_HOME/jre/lib 目录中或者 --Xbootclasspath 参数指定的目录中进行查找,如果找到就加载并返回该Class ,如果没有找到则交给子加载器 ExtClassLoader。
4) ExtClassLoader 则在 $JAVA_HOME/jre/lib/ext 目录中或者系统属性 java.ext.dir 所指的目录中进行查找,如果找到就加载并返回该Class, 找不到则交给 AppClassLoader。
5)AppClassLoader 则在 Classpath 目录中或者系统属性 java.class.path 指定的目录中进行查找,如果找到就加载并返回改Class,找不到就交给我们自定义的类加载器 ,如果还找不到则抛出异常。
为了更好的理解类加载的步骤,我们来分析一下JDK8的ClassLoader源码,首先我们先看ClassLoader的loadClass方法,代码如下所示:
protected Class> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class> c = findLoadedClass(name); // ... 1
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false); // ... 2
} else {
c = findBootstrapClassOrNull(name); // ... 3
}
} 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.
long t1 = System.nanoTime();
c = findClass(name); // ... 4
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
1) 避免重复加载,如果加载过一次 Class ,就不需要再次加载,而是直接读取已经加载的 Class。
2)更加安全,如果不使用双亲委托模式,就可以自定义一个 String 类来替代系统的 String 类,这显然会造成安全隐患,采用双亲委托模式会使得系统的 String 类在 Java 虚拟机启动时就被加载,也就无法自定义 String 类来替代系统的 String 类,除非我们修改类加载器搜索类的默认算法。还有一点, 只有两个类名一致并且被同一个类加载器加载的类, Java 虚拟机才会认为它们是同一个类 想要骗过 Java 虚拟机显然不会那么容易。
系统提供的类加载器只能够加载指定目录下的jar包和Class文件,如果想要加载网络上的或者D盘某一文件中的 jar 包和 Class 文件则需要自定义 ClassLoader 。实现自定义 ClassLoader 需要如下两个步骤:
1)自定义一个类加载器并继承抽象类ClassLoader。
2)复写findClass方法,并在findClass方法中调用defineClass方法。
下面我们就自定义一个ClassLoader用来加载位于D:\lib的Class文件。首先编写测试类并生成Class文件,如下所示:
public class Test{
public void test(){
System.out.println("I'm the test class on disk D");
}
}
将这个Test.java文件放到D:\lib目录中,使用CMD命令进入D:\lib目录中,执行javac Test.java对该java文件进行编译,这时会在 D:\lib 中生成 Test.class文件 。接下来在 Eclipse 中创建一个 Java Project,编写自定义 ClassLoader ,如下所示:
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class MyClassLoader extends ClassLoader{
private String path;
public MyClassLoader(String path) {
this.path = path;
};
@Override
protected Class> findClass(String name) throws ClassNotFoundException {
// TODO Auto-generated method stub
Class> clazz = null;
byte[] classData = loadClassData(name); // ... 1
if(classData == null) {
throw new ClassNotFoundException();
}else {
clazz = defineClass(name,classData,0,classData.length); // ... 2
}
return clazz;
}
private byte[] loadClassData(String name) {
String fileName = getFileName(name);
File file = new File(path,fileName);
InputStream in = null;
ByteArrayOutputStream out = null;
try {
in = new FileInputStream(file);
out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = 0;
while((length = in.read(buffer)) != -1) {
out.write(buffer,0,length);
}
return out.toByteArray();
}catch(IOException e) {
e.printStackTrace();
}finally {
try {
if(in!=null) {
in.close();
}
}catch(IOException e) {
e.printStackTrace();
}
try {
if(out!=null) {
out.close();
}
}catch(IOException e) {
e.printStackTrace();
}
}
return null;
}
private String getFileName(String name) {
int index = name.lastIndexOf(".");
if(index == -1) {
return name + ".class";
}else {
return name.substring(index + 1) + ".class";
}
}
}
注释1处的 loadClassData 方法会获得 class 文件的字节码数组,并在注释2处调用 defineClass 方法将 class 文件的字节码数组转为 Class 类的实例,在loadClassData 方法中要对流进行操作,关闭流的操作要放在 finally 语句块中,并且要对 in 和 out 分别使用try-catch 语句,如果 in 和 out 共同在一个 try- catch 语句中,假设 in.close() 发生异常,就无法执行 out.close()。 最后我们来验证 DMyClassLoader 是否可用,代码如下所示:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ClassLoaderTest {
public static void main(String[] args) {
MyClassLoader loader = new MyClassLoader("D:\\lib"); // ... 1
try {
Class> clazz = loader.loadClass("Test"); // ... 2
if (clazz != null) {
Object test = clazz.newInstance();
System.out.println("test 的类加载器为: " + test.getClass().getClassLoader());
Method method = clazz.getDeclaredMethod("test", null);
method.invoke(test,null); // ... 3
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
test 的类加载器为: MyClassLoader@4e25154f
I'm the test class on disk D
使用MyClassLoader来加载Class文件,从上面的输出可以看出,Test.class文件成功加载到JVM,并且Test 的 test 方法也正确执行。
Java中的 ClassLoader 可以加载jar文件和Class文件(本质是加载Class文件),这一点在Android中并不适用,因为无论是DVM还是ART,他们加载的不再是Class文件,而是dex文件,这就需要重新设计ClassLoader相关类。
Android 中的 ClassLoader 类型和 Java 中的 ClassLoader 类型类似,也分为两种类型, 分别是系统类加载器和自定义加载器。其中系统类加载器主要包括3种,分别是 BootClassLoader、PathClassLoader 和 DexClassLoader。
1. BootClassLoader
Android 系统启动时会使用 BootClassLoader 来预加载常用类,与 Java 中的 Bootstrap ClassLoader 不同,它并不是由 C/C++ 码实现的,而是由 Java 实现的, BootClassLoader 的代码如下所示:
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;
}
...
}
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, null, librarySearchPath, parent);
}
DexClassLoader的构造方法有如下4个参数。
1)dexPath: dex相关文件路径集合,多个路径用文件分隔符分隔,默认文件分隔符为":"。
2)optimizedDirectory:解压的 dex 文件存储路径,这个路径必须是一个内部存储路径,在一般情况下,使用当前应用程序的私有路径:/data/data/
3)librarySearchPath:包含C/C++库的路径集合,多个路径用文件分隔符分隔,可以为null。
3)parent:父类加载器。
DexClassLoader 继承自 BaseDexClassLoader,方法都在BaseDexClassLoader 中实现。
3. PathClassLoader
Android 系统使用 PathClassLoader 来加载系统类和应用程序的类,代码如下所示:
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);
}
}
在Android中运行一个应用程序一般需要用到几种类型的类加载器呢?收下我们来看如下代码:
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ClassLoader classLoader = MainActivity.class.getClassLoader();
while (classLoader != null) {
Log.d(TAG, classLoader.toString());
classLoader = classLoader.getParent();
}
}
}
首先我们得到 MainActivity 的类加载器,然后通过Log打印出来,接着通过循环打印出当前类的类加载器的父类加载器,直到没有父类加载器实终止循环,打印结果如下所示:
07-27 07:03:57.199 5967-5967/com.lx.class_loader D/MainActivity: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.lx.class_loader-1/base.apk"],nativeLibraryDirectories=[/data/app/com.lx.class_loader-1/lib/x86, /vendor/lib, /system/lib]]]
07-27 07:03:57.199 5967-5967/com.lx.class_loader D/MainActivity: java.lang.BootClassLoader@88d5d94
1)ClassLoader 是一个抽象类,其中定义了 ClassLoader 的主要功能。 BootClassLoader 是它的内部类。
2)SecureClassLoader 类和 JDK8 中的 SecureClassLoader 类的代码是一样的,它继承了抽象类 ClassLoader。SecureClassLoader 并不是 ClassLoader 的实现类,而是拓展了 ClassLoader 类,加入了权限方面的功能,加强了 ClassLoader 的安全性
3)URLClassLoader 类和 JDK8 中的 URLClassLoader 类的代码是一样的,它继承自 SecureClassLoader ,用来通过 URL 路径从 jar 文件和文件夹中加载类和资掘。
4)InMemoryDexClassLoader 是 Android 8.0 新增的类加载器,继承自 BaseDexClassLoader ,用于加载内存中的 dex 文件。
5)BaseDexClassLoader 继承自 ClassLoader ,是抽象类 ClassLoader 的具体实现类, PathClassLoader 、DexClassLoader、 InMemoryDexClassLoader 都继承自它。
Android中的 ClassLoader 同样遵循了双亲委托模式,ClassLoader 的加载方法为loadClass 方法,这个方法被定义在抽象类ClassLoader 中,代码如下所示:
protected Class> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class> c = findLoadedClass(name); // ... 1
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false); // ... 2
} else {
c = findBootstrapClassOrNull(name); // .... 3
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {// ... 4
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name); // ... 5
}
}
return c;
}
protected Class> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
在 findClass 方法中直接抛出了异常,这说明 findClass 方法需要子类来实现,BaseDexClassLoader 的代码如下所示:
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, null); // ... 1
if (reporter != null) {
reportClassLoaderChain();
}
}
...
@Override
protected Class> findClass(String name) throws ClassNotFoundException {
List suppressedExceptions = new ArrayList();
Class c = pathList.findClass(name, suppressedExceptions); // ... 2
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;
}
...
}
在 BaseDexClassLoader 的构造方法的注释1处创建了 DexPathList,在注释2处调用了 DexPathList 的findClass 方法,代码如下所示:
public Class> findClass(String name, List suppressed) {
for (Element element : dexElements) { // ... 1
Class> clazz = element.findClass(name, definingContext, suppressed); // ... 2
if (clazz != null) {
return clazz;
}
}
if (dexElementsSuppressedExceptions != null) {
suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
}
return null;
}
libcore/dalvik/src/main/java/dalvik/system/DexPathlist.java
/*package*/ static class Element {
private final File path;
private final DexFile dexFile;
private ClassPathURLStreamHandler urlHandler;
private boolean initialized;
public Element(DexFile dexFile, File dexZipPath) {
this.dexFile = dexFile;
this.path = dexZipPath;
}
public Element(DexFile dexFile) {
this.dexFile = dexFile;
this.path = null;
}
public Element(File path) {
this.path = path;
this.dexFile = null;
}
...
public Class> findClass(String name, ClassLoader definingContext,
List suppressed) {
return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
: null; // ... 1
}
...
}
从 Element 的构造方法可以看出,其内部封装了 DexFile ,它用于加载dex。在注释1处如果dexFile不为 null 就会调用DexFile 的loadClassBinaryName方法,代码如下所示:
public Class loadClassBinaryName(String name, ClassLoader loader, List suppressed) {
return defineClass(name, loader, mCookie, this, suppressed);
}
在 loadClassBinaryName 方法中调用了defineClass方法,代码如下所示:
libcore/dalvik/src/main/java/dalvik/system/DexFile.java
private static Class defineClass(String name, ClassLoader loader, Object cookie,
DexFile dexFile, List suppressed) {
Class result = null;
try {
result = defineClassNative(name, loader, cookie, dexFile); // ... 1
} catch (NoClassDefFoundError e) {
if (suppressed != null) {
suppressed.add(e);
}
} catch (ClassNotFoundException e) {
if (suppressed != null) {
suppressed.add(e);
}
}
return result;
}
BootClassLoader 是在何时被创建的呢?这得先从 Zygote 进程开始说起, Zygotelnit 的 main 方法如下所示:
public static void main(String argv[]) {
...
try {
...
if (!enableLazyPreload) {
...
preload(bootTimingsTraceLog);
...
} else {
Zygote.resetNicePriority();
}
...
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
zygoteServer.closeServerSocket();
}
...
}
在ZygoteInit 的 main 方法中调用了 preload 方法,而 平reload 方法又调用了ZygoteInit 的 preloadClasses 方法,代码如下所示:
frameworks/base/core/java/com/android/internal/os/Zygotelnit.java
...
private static final String PRELOADED_CLASSES = "/system/etc/preloaded-classes";
...
private static void preloadClasses() {
final VMRuntime runtime = VMRuntime.getRuntime();
InputStream is;
try {
// 获取/system/etc/preloaded-classes文件的FileInputStream
is = new FileInputStream(PRELOADED_CLASSES); // ... 1
} catch (FileNotFoundException e) {
Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
return;
}
...
try {
// 将FileInputSteam
BufferedReader br
= new BufferedReader(new InputStreamReader(is), 256); // ... 2
int count = 0;
String line;
while ((line = br.readLine()) != null) { // ... 3
// 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(line, true, null); // ... 4
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) {
Log.e(TAG, "Error preloading " + line + ".", t);
if (t instanceof Error) {
throw (Error) t;
}
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
}
throw new RuntimeException(t);
}
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
}
Log.i(TAG, "...preloaded " + count + " classes in "
+ (SystemClock.uptimeMillis()-startTime) + "ms.");
} catch (IOException e) {
Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
} finally {
...
}
}
preloadClasses 方法用于 Zygote 进程初始化时预加载常用类。在注释1处获取 PRELOADED_CLASSES (值为 system/etc/preloaded-classes )文件的 FilelnputStream, preloaded-classes 文件中存有预加载类的目录,这个文件在系统源码中的路径为 frameworks/base/preloaded-classes,这里列举一些 preloaded-classes 文件中的预载类名称, 如下所示:
android.app.ApplicationLoaders
android.app.ApplicationPackageManager
android.app.ApplicationPackageManager$OnPermissionsChangeListenerDelegate
android.app.ApplicationPackageManager$ResourceName
android.app.ContentProviderHolder
android.app.ContentProviderHolder$1
android.app.ContextImpl
android.app.Contextimpl$ApplicationContentResolver
android.app.DexLoadReporter
android.app.Dialog
android.app.Dialog$ListenersHandler
android.app.DownloadManager
android.app.Fragment
@CallerSensitive
public static Class> forName(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException
{
if (loader == null) {
loader = BootClassLoader.getInstance(); // ... 1
}
Class> result;
try {
result = classForName(name, initialize, loader); // ... 2
} catch (ClassNotFoundException e) {
Throwable cause = e.getCause();
if (cause instanceof LinkageError) {
throw (LinkageError) cause;
}
throw e;
}
return result;
}
@FastNative
static native Class> classForName(String className, boolean shouldInitialize,
ClassLoader classLoader) throws ClassNotFoundException;
private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
...
if (parsedArgs.invokeWith != null) {
...
} else {
ClassLoader cl = null;
if (systemServerClasspath != null) {
cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion); // ... 1
Thread.currentThread().setContextClassLoader(cl);
}
/*
* Pass the remaining arguments to SystemServer.
*/
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}
/* should never reach here */
}
在注释1处调用了createPathClassLoader方法,代码如下所示:
static ClassLoader createPathClassLoader(String classPath, int targetSdkVersion) {
String libraryPath = System.getProperty("java.library.path");
return ClassLoaderFactory.createClassLoader(classPath, libraryPath, libraryPath,
ClassLoader.getSystemClassLoader(), targetSdkVersion, true /* isNamespaceShared */,
null /* classLoaderName */);
}
在 createPathClassLoader 方法中有调用了 ClassLoaderFactory 的 createClassLoader 方法,代码如下所示:
public static ClassLoader createClassLoader(String dexPath,
String librarySearchPath, ClassLoader parent, String classloaderName) {
if (isPathClassLoaderName(classloaderName)) {
return new PathClassLoader(dexPath, librarySearchPath, parent);
} else if (isDelegateLastClassLoaderName(classloaderName)) {
return new DelegateLastClassLoader(dexPath, librarySearchPath, parent);
}
throw new AssertionError("Invalid classLoaderName: " + classloaderName);
}