Android源码的食用方法
0x00 Prelude
有时候感觉发自内心地喜欢Android。不仅是因为我们可以创造「小而美」的应用程序,还因为Google提供了很好的售后服务。
前两天了解了一些关于ClassLoader的东西,我想真正的学习模式应该是在用到的时候再去查找,比如公司需要真正开发一套插件框架,我再去学习,这样的动机下可能动力会更足。现在是处于学习阶段,虽然不知道看了有什么用,但还是去看吧。
Android源码很庞大,要完整看完是不太可能,我想起高中数学老师常常教育我们的一句话:「不要想着一口吃成个胖子。」所以可以慢慢来。好在我们可以站在巨人的肩膀上,已经有很多人写了源码的阅读笔记,比如罗升阳的博客和书。
0x01 怎么找到具体的类
ClassLoader.java可以在Android Studio的android.jar中看到,只要按住CMD点击左键就可以跳转了,这是因为Android Studio下载sdk的时候attach了源码到android.jar上。但是DexClassLoade.java的源码打开的时候,看到的就是反编译出来的代码了;
这是因为android.jar只会attach到一些常用的源码,DexClassLoader.java这个类,是在Dalvik目录下的,也许不是很常用,所以我们看到的是反编译出来的源码。反编译出来的源码没有注释,可读性也差很多。比如,我们看到的是这样的:
public BaseDexClassLoader(String dexPath, File optimizedDirectory, String libraryPath, ClassLoader parent) {
throw new RuntimeException("Stub!");
}
这个的意思是,函数具体的实现都放在ROM中了,不在这里暴露。
我们可以去谷歌AOSP的网站上去看源码。比如android.jar,它的内容基本都在https://android.googlesource.com/platform/frameworks/base/+/android-6.0.1_r21/core/java/android/这个路径下。但是内容太多,找了一段时间也没找到BaseDexClassLoader.java的位置,怎么办?
这时候可以借助Google,直接搜索:
where is BaseDexClassLoader.java,可以看到,贴心的Google第一条给出了API的地址,第二条给出了BaseDexClassLoader在AOSP中的地址。
0x02 插件的加载
插件装载的执行顺序是:
BaseDexClassLoader--->pathList.findClass(name)--->loadClassBinaryName(),最终指向了一个native方法loadClassBinaryName()。
/**
* Finds the named class in one of the dex files pointed at by
* this instance. This will find the one in the earliest listed
* path element. If the class is found but has not yet been
* defined, then this method will define it in the defining
* context that this instance was constructed with.
*
* @return the named class or {@code null} if the class is not
* found in any of the dex files
*/
public Class findClass(String name) {
for (Element element : dexElements) {
DexFile dex = element.dexFile;
if (dex != null) {
Class clazz = dex.loadClassBinaryName(name, definingContext);
if (clazz != null) {
return clazz;
}
}
}
return null;
}
好了,明天我们看看Robile中的Plugin为什么重写了loadClass()方法。
-NOV23