一直在研究 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 中
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) 這個包是系統皮膚實現的一個包