Android 啟動載入jar包 init.rc BOOTCLASSPATH
一直在研究 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 中
[java] view plaincopyprint?-
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) 這個包是系統面板實現的一個包