关系图
classloader是所有classloader的父类(继承关系)
bootclssloader是所有classloader的parent(委托关系)
先做一个demo,代码如下
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.v("wanbai", "Activity的类加载加载器:" + Activity.class.getClassLoader() + ">>>code == " + Activity.class.getClassLoader().hashCode() );
Log.v("wanbai", "Context的类加载加载器:" + Context.class.getClassLoader() + ">>>code == " + Context.class.getClassLoader().hashCode());
Log.v("wanbai", "ListView的类加载器:" + ListView.class.getClassLoader() + ">>>code == " + ListView.class.getClassLoader().hashCode());
Log.v("wanbai", "------------------------------------------------------------------------------------------------------------------\n");
Log.v("wanbai", "MainActivity的类加载加载器:" + MainActivity.class.getClassLoader() + ">>>code == " + MainActivity.class.getClassLoader().hashCode() );
Log.v("wanbai", "应用程序默认加载器1:" + getClassLoader() + ">>>code == " + getClassLoader().hashCode());
Log.v("wanbai", "应用程序默认加载器2:" + this.getClass().getClassLoader() + ">>>code == " + this.getClass().getClassLoader().hashCode());
Log.v("wanbai", "应用程序默认加载器3:" + MainActivity.this.getClass().getClassLoader() + ">>>code == " + MainActivity.this.getClass().getClassLoader().hashCode());
Log.v("wanbai", "系统类加载器:" + ClassLoader.getSystemClassLoader() + ">>>code == " + ClassLoader.getSystemClassLoader().hashCode());
Log.v("wanbai", "------------------------------------------------------------------------------------------------------------------\n");
Log.v("wanbai", "打印应用程序默认加载器的委派机制:");
ClassLoader classLoader = getClassLoader();
while (classLoader != null) {
Log.v("wanbai", "类加载器:" + classLoader);
classLoader = classLoader.getParent();
}
Log.v("wanbai", "------------------------------------------------------------------------------------------------------------------\n");
Log.v("wanbai", "打印系统加载器的委派机制:");
classLoader = ClassLoader.getSystemClassLoader();
while (classLoader != null) {
Log.v("wanbai", "类加载器:" + classLoader);
classLoader = classLoader.getParent();
}
}
}
打印如下:
Activity的类加载加载器:java.lang.BootClassLoader@c692ed4>>>code == 208219860
Context的类加载加载器:java.lang.BootClassLoader@c692ed4>>>code == 208219860
ListView的类加载器:java.lang.BootClassLoader@c692ed4>>>code == 208219860
------------------------------------------------------------------------------------------------------------------
MainActivity的类加载加载器:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/lib/arm64, /system/lib64, /system/vendor/lib64]]]>>>code == 17152125
应用程序默认加载器1:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/lib/arm64, /system/lib64, /system/vendor/lib64]]]>>>code == 17152125
应用程序默认加载器2:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/lib/arm64, /system/lib64, /system/vendor/lib64]]]>>>code == 17152125
应用程序默认加载器3:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/lib/arm64, /system/lib64, /system/vendor/lib64]]]>>>code == 17152125
系统类加载器:dalvik.system.PathClassLoader[DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /system/vendor/lib64, /system/lib64, /system/vendor/lib64]]]>>>code == 190042994
------------------------------------------------------------------------------------------------------------------
打印应用程序默认加载器的委派机制:
类加载器:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/lib/arm64, /system/lib64, /system/vendor/lib64]]]
类加载器:java.lang.BootClassLoader@c692ed4
------------------------------------------------------------------------------------------------------------------
打印系统加载器的委派机制:
类加载器:dalvik.system.PathClassLoader[DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /system/vendor/lib64, /system/lib64, /system/vendor/lib64]]]
类加载器:java.lang.BootClassLoader@c692ed4
activity创建过程:
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
}
这个demo说明,
1.凡是属于android系统的类,都是由bootclassloader来加载,如:Application,Activity
2.凡是自定义类,都是pathclassloader来加载,如:MyApplication,MyActivity
3.MainActivity.class.getclassloader 等于 this.getclass().getclassloader 等于MainActivity.this.getclass().getclassloader。
表示的是,加载MainActivity.class这个类的classloader是什么,
通过activity的实例化研究我们发现,在ActivityThread.performLaunchActivity里。实例化activity用的classloader,为appContext的classloader。
4.demo中getClassloader,实际调用到contextwrraper,再调用到contextImpl的getclassloader.熟悉activity创建过程就明白,上面的appcontext就是activity的contextImpl实例
所以,就会理解getclassloader和MainActivity.class.getclassloader为什么会一致了
5.Classloader.getsystemclassloader实际也是返回pathclassloader,但是这个classloader用的极少,后面再做分析
ClassLoader的作用
1.classloader作用就是查找加载类。
classloader加载类采用双亲委托模式,loadclass向上委托,findclass向下查找
ClassLoader.java
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded 找缓存
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) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
return c;
}
一般情况下,classloader的子类,不会覆写loadclass方法。只会覆写findclass方法
比如我们熟悉的BaseDexClassLoader.java 没有覆写loadclass,findclass方法如下
@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;
}
继续查看DexPathList的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;
}
Element是DexPathList的内部类,继续查看
public Class<?> findClass(String name, ClassLoader definingContext,
List<Throwable> suppressed) {
return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
: null;
}
继续查看同包下的DexFile.java
public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) {
return defineClass(name, loader, mCookie, this, suppressed);
}
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)
最终通过native方法加载出class
分析BootClassLoader
Bootclassloader是Classloader的内部类,是android中所有classloader的parent,可见性为包内可见,但是我们无法使用
在Android系统启动时创建,用于加载一些Framework层的类。
bootclassloader创建于zygoteInit的main方法的preload函数开始
1.main方法内
2.preload内
3.preloadClasses内。注意此时loader为null
4.forName方法内
到此,BootClassloader就创建完成了,并且它是一个单例,
BooClassloader的加载范围
分析PathClassLoader
pathclassloader主要用于加载 已经安装到android系统中的apk文件以及系统类(/data/app 目录),是android默认使用的类加载器
在App启动的时候创建,主要用于加载/data/app/xxx.xxx.xxx/sample-1/base.apk里面的类以及系统类
(实际上也可以加载外部apk,8.0以后更是更DexClassLoader完全一样了)
PathclassLoader创建分为两种,一种是systemserver进程的创建,一种是应用程序进程中的创建,
1.先看应用程序进程中pathclassloader创建过程。
肯定从应用启动流程中找,看图
1.从 handleBindApplication()开始
app = data.info.makeApplication(data.restrictedBackupMode, null);
2.LoadedApk的makeApplication方法
3.LoadedApk的getClassLoader方法
@UnsupportedAppUsage
public ClassLoader getClassLoader() {
synchronized (this) {
if (mClassLoader == null) {
createOrUpdateClassLoaderLocked(null /*addedPaths*/);
}
return mClassLoader;
}
}
4.LoadedApk的 createOrUpdateClassLoaderLocked方法
5.ApplicationLoaders的getClassLoader方法
6.ClassloaderFactory的createClassLoader方法
public static ClassLoader createClassLoader(String dexPath,
String librarySearchPath, String libraryPermittedPath, ClassLoader parent,
int targetSdkVersion, boolean isNamespaceShared, String classloaderName) {
final ClassLoader classLoader = createClassLoader(dexPath, librarySearchPath, parent,
classloaderName);
boolean isForVendor = false;
for (String path : dexPath.split(":")) {
if (path.startsWith("/vendor/")) {
isForVendor = true;
break;
}
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "createClassloaderNamespace");
String errorMessage = createClassloaderNamespace(classLoader,
targetSdkVersion,
librarySearchPath,
libraryPermittedPath,
isNamespaceShared,
isForVendor);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (errorMessage != null) {
throw new UnsatisfiedLinkError("Unable to create namespace for the classloader " +
classLoader + ": " + errorMessage);
}
return classLoader;
}
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);
}
最终是通过ClassloaderFactory的工厂方法构建成的
2.再看systemserver进程中pathclassloader创建过程(ams所在进程,非app应用进程)
patchclassloader的创建过程,也是从zygoteinit类开始的。
forksystemserver中
handlesystemserver是在子进程中被调用的,就是刚启动的这个程序
createPathClassLoader中
经过重重的重载方法,最后new出来了一个PathClassLoader.
分析DexClassLoader
它和pathclassloader,都继承自BaseDexClassLoader.
android用于插件化,热修复,主要就是依靠的dexclassloader。
PathClassLoader 和 DexClassLoader 都能加载外部的 dex/apk,只不过区别是 DexClassLoader 可以指定 optimizedDirectory,
也就是 dex2oat 的产物 .odex 存放的位置,而 PathClassLoader 只能使用系统默认位置。但是这个 optimizedDirectory 在 Android 8.0 以后也被舍弃了,
只能使用系统默认的位置了。
8.0以前DexClassLoader构造
public DexClassLoader(String dexPath, String optimizedDirectory,
String librarySearchPath, ClassLoader parent) {
super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);
}
8.0之后,DexClassLoader也变成PathClassLoader一样了
public DexClassLoader(String dexPath, String optimizedDirectory,
String librarySearchPath, ClassLoader parent) {
super(dexPath, null, librarySearchPath, parent);
}
public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) {
super(dexPath, null, librarySearchPath, parent);
}
热修复的原理是
1.取出旧的Pathclassloader的 pathlist,再取出其中的的dexElementsA[].
2.用一个新的classloader,加载出dex,再同样取出dexElementsB[].
3.把这B放在A之前,就能简单的做热修复了