一直在研究 Dalvik 的实现,今天突然想起一件事情,我们默认可以用 java.lang.Object 等系统类,他是在什么时候被加载进来了呢,我们自己的类是否可以这样预先加载进去呢?
顺着这个思路,再回顾一下原来对 Zygote 启动时的流程,探索一番!
Zygote 启动流程(网上有很多的分析不太详诉):
>>> Kernel 启动
>>> 启动 init 程序,此程序解析 init.rc 进行执行
>>> 在 init.rc 中有启动 zygote 代码
>>> zygote 启动后最后 fork 出 system_server 进行系统服务
>>> zygote 等待 socket 事件准备孵化用户进程
在 Zygote 的启动中有如下关键调用:
AppRuntime.start 启动 com.android.internal.os.ZygoteInit 类处理
既然这时能够调用 java 类处理了,哪么系统基础类肯定在这之前准备好了,顺着这个向里面看
AppRuntime 继承 AndroidRuntime
AndroidRuntime 的 start 函数,调用了 JNI_CreateJavaVM 函数生成虚拟机
JNI_CreateJavaVM 是 jni.c 中,也就是 libdvm.so 中的一个函数
JNI_CreateJavaVM 中调用了 dvmStartup 函数启动一个虚拟机
dvmStartup 调用了setCommandLineDefaults 实现参数默认值。里面有最为重要的获取环境变理 BOOTCLASSPATH 方法。
回头看一下 init.rc 中
view plainprint?
export BOOTCLASSPATH /system/framework/core.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/core-junit.jar
原来是在这里指定了一些基础类的 jar 包
继续看代码
dvmStartup 中调用了 setCommandLineDefaults 设置默认 BOOTCLASSPATH
dvmStartup 中调用了dvmClassStartup 加载默认启动类
dvmClassStartup 中调用了 processClassPath 处理类路径,其实就是 BOOTCLASSPATH 中的值。
processClassPath 中建立结构体 ClassPathEntry 来存储一个路径信息
processClassPath 中调用了 prepareCpe 准备类路径节点
prepareCpe 中调用了dvmJarFileOpen 打开一个 jar 包
所有被加载的 Jar 包类都放到全局对像 gDvm.bootClassPath 中存储。
gDvm.bootClassPath 对像的结尾都是用一个特殊的结构体来表示的,这里是 kind = kCpeLastEntry 表示是最后一个类路径节点,因些不用另外一个变量表示大小。
大概清楚了!
-------------------------------------- 无聊的分割线 --------------------------------------
哪么我们想增加一个基础包给系统使用,大概有几种方法:
改 init.rc 的 BOOTCLASSPATH 环境变量初始值
在 zygote 启动前改动 BOOTCLASSPATH 环境变量
在 zygote 启动后想办法让他加载一个 jar 包
到此发现,系统启动前后环环相扣,并助实现的都是可扩展化,轻易不硬编码到代码中。
以后会继续深入研究一下其它东西的加载,比如:很有意思的一个 apk (ramework-res.apk) 这个包是系统皮肤实现的一个包
顺着这个思路,再回顾一下原来对 Zygote 启动时的流程,探索一番!
Zygote 启动流程(网上有很多的分析不太详诉):
>>> Kernel 启动
>>> 启动 init 程序,此程序解析 init.rc 进行执行
>>> 在 init.rc 中有启动 zygote 代码
>>> zygote 启动后最后 fork 出 system_server 进行系统服务
>>> zygote 等待 socket 事件准备孵化用户进程
在 Zygote 的启动中有如下关键调用:
AppRuntime.start 启动 com.android.internal.os.ZygoteInit 类处理
既然这时能够调用 java 类处理了,哪么系统基础类肯定在这之前准备好了,顺着这个向里面看
AppRuntime 继承 AndroidRuntime
AndroidRuntime 的 start 函数,调用了 JNI_CreateJavaVM 函数生成虚拟机
JNI_CreateJavaVM 是 jni.c 中,也就是 libdvm.so 中的一个函数
JNI_CreateJavaVM 中调用了 dvmStartup 函数启动一个虚拟机
dvmStartup 调用了setCommandLineDefaults 实现参数默认值。里面有最为重要的获取环境变理 BOOTCLASSPATH 方法。
回头看一下 init.rc 中
view plainprint?
export BOOTCLASSPATH /system/framework/core.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/core-junit.jar
原来是在这里指定了一些基础类的 jar 包
继续看代码
dvmStartup 中调用了 setCommandLineDefaults 设置默认 BOOTCLASSPATH
dvmStartup 中调用了dvmClassStartup 加载默认启动类
dvmClassStartup 中调用了 processClassPath 处理类路径,其实就是 BOOTCLASSPATH 中的值。
processClassPath 中建立结构体 ClassPathEntry 来存储一个路径信息
processClassPath 中调用了 prepareCpe 准备类路径节点
prepareCpe 中调用了dvmJarFileOpen 打开一个 jar 包
所有被加载的 Jar 包类都放到全局对像 gDvm.bootClassPath 中存储。
gDvm.bootClassPath 对像的结尾都是用一个特殊的结构体来表示的,这里是 kind = kCpeLastEntry 表示是最后一个类路径节点,因些不用另外一个变量表示大小。
大概清楚了!
-------------------------------------- 无聊的分割线 --------------------------------------
哪么我们想增加一个基础包给系统使用,大概有几种方法:
改 init.rc 的 BOOTCLASSPATH 环境变量初始值
在 zygote 启动前改动 BOOTCLASSPATH 环境变量
在 zygote 启动后想办法让他加载一个 jar 包
到此发现,系统启动前后环环相扣,并助实现的都是可扩展化,轻易不硬编码到代码中。
以后会继续深入研究一下其它东西的加载,比如:很有意思的一个 apk (ramework-res.apk) 这个包是系统皮肤实现的一个包