- 反射的两种方式
1、Classloder.loaderClass(String name)
2、Class.forName(String name)
两者最大的区别是
Class.forName得到的class是已经初始化完成的
Classloder.loaderClass得到的class是还没有初始化的
ActivityThread.java 中有一段
@UnsupportedAppUsage
private void handleBindApplication(AppBindData data) {
....
..
// The test context's op package name == the target app's op package name, because
// the app ops manager checks the op package name against the real calling UID,
// which is what the target package name is associated with.
final ContextImpl instrContext = ContextImpl.createAppContext(this, pi,
appContext.getOpPackageName());
try {
final ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate instrumentation "
+ data.instrumentationName + ": " + e.toString(), e);
}
}
调用了classloader的loadclass方法初始化mInstrumentation ,这里 parent.loadClass 就是类加载的双亲委托机制:首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
好处是:避免重复加载 + 避免核心类篡改
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;
}
- 跟踪代码可以知道instrContext.getClassLoader(); 得到的classloader是PathClassLoader.java
就是调用PathClassLoader 的 findClass(name)
而public class PathClassLoader extends BaseDexClassLoader 且没有重写父类的findClass方法,所以调用
BaseDexClassLoader 的 findClass
代码路径:dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
protected Class<?> findClass(String name) throws ClassNotFoundException {
// First, check whether the class is present in our shared libraries.
if (sharedLibraryLoaders != null) {
for (ClassLoader loader : sharedLibraryLoaders) {
try {
return loader.loadClass(name);
} catch (ClassNotFoundException ignored) {
}
}
}
// Check whether the class in question is present in the dexPath that
// this classloader operates on.
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;
}
关键一句在 Class c = pathList.findClass(name, suppressedExceptions);
pathList 就是 DexPathList
dalvik/src/main/java/dalvik/system/DexPathList.java,从下面代码看是从dexElements去找
@UnsupportedAppUsage
private Element[] dexElements;
DexPathList(ClassLoader definingContext, String dexPath,
String librarySearchPath, File optimizedDirectory, boolean isTrusted) {
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions, definingContext, isTrusted);
}
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;
}
从上面的代码看出dexElements是个关键,findClass就是从dexElements去找 找到就返回,也就是谁在前面就先被找到,后面的就不找了!!! 这里就涉及到了一个技术 热修复
热修复 目前是比较成熟的技术了
1、获取当前用的pathclassloader
2、通过pathclassloader 反射拿 private Element[] dexElements;
3、将dex补丁包转换成Elements_new 数组(反射makeDexElements)
4、将Elements_new 插入到dexElements数组前面 更新 dexElements