这个技术常用于android插件开发,android加固,,,,(妈的,抄第一代壳的时候,死活看不懂,原来是因为没看过这技术。。),
我还得补一补,,,
classloader
类加载器,听名字就知道用于加载类的,对于安卓层面的话,就是用于加载dex文件
双亲委派
加载dex文件的时候,问一下当前的类加载器有没有加载,没的话,递归问类加载器的超类,这一继承路上,只要dex文件被其中一个classloader加载,其他时候都不用被加载
android的类加载器
1.bootclassloader(加载android框架的)
2.pathclassloader(加载安装到android上的apk文件)
3.dexclassloader(可以加载自己的dex文件),动态加载的关键点
4.baseclassloader(pathclassloader和dexclassloader的父类)
pathclassloader和dexclassloader区别
其实没什么区别,毕竟父类都是baseclassloader,唯一区别在于dexclassloader比pathclassloader多一个存放自己dex文件的参数,
用于加载classloader的时候
// 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);
}
}
// DexClassLoader
public class DexClassLoader extends BaseDexClassLoader {
public DexClassLoader(String dexPath, String optimizedDirectory,
String librarySearchPath, ClassLoader parent) {
super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);
}
}
类加载器如何判断当前的dex文件是否被加载过呢?
findclass方法,看了几篇文章,明白了原理,就是一条一环套一环的线
pathclassloader和dexclassloader都是用它的父类(baseclassloader)的findclass方法,而baseclassloader的findclass方法主要来自dexpathlist的findclass方法,而dexpathlist的findclass方法主要就是对它dexelement集合的遍历查找,而dexelement是来源于makedexelements方法
private static Elempublic class BaseDexClassLoader extends ClassLoader {
private final DexPathList pathList;
...
public BaseDexClassLoader(String dexPath, File optimizedDirectory, String libraryPath, ClassLoader parent){
super(parent);
this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
}
...
}
ent[] 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()]);
}
可以看到,加载文件,并将它分装成element对象。放到elements数组里,而makedexelements是在dexpathlist的构造函数中调用,而dexpathlist的构造在baseclassloader的构造函数中创建,而baseclassloader的创建是在我们用dexclassloader和pathclassloader中使用,
由此我们可以理清楚android加载dex文件的流程:
当我们使用dexclassloader加载dex文件时,dexclassloader调用它的超类baseclassloader,
而baseclassloader由此new dexpathlist,接着dexpathlist使用makedexelements方法加载dex文件,同时将加载好后的文件包装成elements中去,而类加载器使用findclass判断是否加载过该dex文件时,正是通过对elements集合的遍历查找
mclassloader来源于loadedapk.java,可以知道这个loadedapk用于加载apk文件的,而loadedapk对象
有了以上知识,就可以谈一下我们的重点 动态加载activity,ActivityThread类中有一个自己的static对象,然后还有一个ArrayMap存放Apk包名和LoadedApk映射关系的数据结构,
android的动态加载activity
使用反射机制修改类加载器来实现动态加载Activity
1.替换LoadedApk中的mClassLoader
2.合并PathClassLoader和DexClassLoader中的dexElements数组
https://blog.youkuaiyun.com/suyimin2010/article/details/80958712
静态代理
(不会)