首页
社区
课程
招聘
[原创]Android类加载机制之Class.forName与ClassLoader.loadClass
发表于: 2019-12-12 21:37 4335

[原创]Android类加载机制之Class.forName与ClassLoader.loadClass

2019-12-12 21:37
4335

-- 前言:最近使用ClassLoader.findClass去hook类的加载时,发现有些类的加载竟然hook不到,经过一番问大牛,查资料的过程后,发现了另一个用于加载类的API,遂产生了疑问:为啥会存在两种方式去加载类呢???以下是研究所得,菜鸟一个,大牛轻喷。。。

 

本篇的源码基于Android 6.0.1_r77.
先看Class.forName()
路径:/libcore/libart/src/main/java/java/lang/Class.java

实际调用的是Class类的forName(String,boolean,ClassLoader)函数,这里传进去的第一个参数为类名称,第二个参数是一个boolean类型的值为true,而第三个参数就是一个ClassLoader。
继续看这个被调用的forName函数

可以看到实际上调用的就是native方法classForName函数
再来看ClassLoader.loadClass函数
路径:/libcore/libart/src/main/java/java/lang/ClassLoader.java

跟进这个loadClass(String,boolean)函数

可以看到这个函数,首先查找这个类是否已经加载过,如果没有加载,优先执行parent(参数类型也是ClassLoader)的loadClass函数,这里要引入一个ClassLoader的委托机制,即当我们通过ClassLoader A加载目标类的时候,它首先会委托自己的parent进行加载,而parent可能还会进一步地去委托自己的parent去加载,如此递进,如果被委托的Java Class对象加载不了目标类的话,则由委托者尝试加载。这里的parent应该是bootClassLoader
假设此时,如果parent加载的class为null,进一步查看findClass的内容

可以发现这里直接抛出一个异常。。。。实际上这个类的实现由其子类实现也就是BootClassLoader

可以看到实际上也调用的Class类的classForName函数;

 

跟踪Class的classForName函数

 

可以看到实际上这个函数由native层实现,查看这个函数的具体实现
路径:/art/runtime/native/java_lang_Class.cc

可以看到实际上最终这个函数调用的是ClassLinker的FindCLass去加载的java类函数,而使用Class.forName与ClassLoader.loadClass最终的不同点在于在java层最终调用Class.classForName函数时传进来的第二个参数的不同而已,我们来看这个初始化函数
路径:/art/runtime/class_linker.cc

这个函数实际上调用这个类的InitializeClass函数,类的初始化函数????
进一步查看这个函数,发现这个函数首先进行一些类的校验,然后进行父类的初始化

在父类进行初始化后,对本类的一些静态的变量进行初始化

 

实际上,这两个API区别在于,如果这个类被重载或者有静态变量需要初始化则会调用Class.forName函数,否则调用ClassLoader.findClass函数进行类的加载。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2019-12-15 17:04 被Simp1er编辑 ,原因:
收藏
免费 0
支持
分享
最新回复 (3)
雪    币: 14873
活跃值: (6098)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
结论是?
2019-12-13 08:13
0
雪    币: 183
活跃值: (1223)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
还会走bootclassloader的findclass嘛。
2019-12-13 09:55
0
雪    币: 1380
活跃值: (1626)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
一切都走ClassLoader.findClass这个不就可以了
2019-12-13 11:17
0
游客
登录 | 注册 方可回帖
返回
//