1.ART雙親委托機制:
PathClassLoader,DexClassLoader --繼承自--> BaseDexClassLoader --繼承自--> ClasssLoader
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 {
//若頂級類加載器父類是空 則調用這個方法 這個方法是又ClassLoader類提供的private方法,預設傳回null
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;
}
protected final Class<?> findLoadedClass(String name) {
ClassLoader loader;
if (this == BootClassLoader.getInstance())
loader = null;
else
loader = this;
return VMClassLoader.findLoadedClass(loader, name);
}
//VMClassLoader.findLoadedClass是一個native方法,其實作在art/runtime/native/lava_lang_VMClassLoader: VMClassLoader_findLoadedClass方法
首次加載類 檢察類是否加載過,如果加載過直接傳回,由目标classLoader的父類去加載,加載成功直接傳回,
加載失敗則再次尋找父類的父類去加載,如果目前類是BootClassLoader則調用VMClassLoader.findLoadedClass去加載,成功則傳回,失敗則由原始目标classLoader的findClass去加載
BaseDexClassLoader -> findClass -> pathList.findClass() ->
//DexPathList
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;
}
2.反射擷取類中的dexElements (MutliDex插樁)
通過反射我們最終可以去修改DexPathList中的dexElements數組 -> BaseDexClassLoader:pathList(DexPathList):dexElements(Elements[])
2.1.反射擷取BaseDexClassLoader的成員變量pathList(DexPathList)
2.2.反射擷取DexPathList的成員變量dexElements(Elements[])
2.3.修改dexElements ()