Dalvik VM start up process

來源:互聯網
上載者:User
Dalvik VM的啟動過程解析

Dalvik 虛擬機器的啟動要從android另一個著名的模組,Zygote,說起。

 

我們知道android系統中,每一個java應用被設計成可以運行在一個單獨的Linux進程中。而每個該進程都包含一個運行中的dalvik虛擬機器執行個體,用來執行該應用中的java位元組碼。很多java基礎類(比如,java.lang.*)和一些系統級的共用性資源(drawable/color...)等幾乎會被所有的進程使用。如果每次虛擬機器啟動後都去載入這些資源,必然是個很大浪費。其實每個虛擬機器裡載入這些資源的過程都是一模一樣的。Android系統就使用一個巧妙的方式解決這個問題。那就是Zygote的用處。

 

由於本系列文章的重點不是Zygote,而且Zygote的實現也很簡單,對於它的介紹網上已經很多了,本文不準備詳細介紹Zygote。而是簡單的說明一下它和Dalvik相連的部分。

Zygote其實是一個系統級本地服務,在init.rc裡定義(如下所示),在系統啟動早期被啟動起來。它原始名字是app_process(原始碼frameworks/base/cmds/app_process/app_main.cpp):

// @ system/core/rootdir/int.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server    class main    socket zygote stream 666    onrestart write /sys/android_power/request_state wake    onrestart write /sys/power/state on    onrestart restart media    onrestart restart netd

該服務會在啟動後載入前文提到基礎類和資源,並且建立socket(名稱是如上所示的zygote)。後面其他的java應用程式啟動後,AMS(ActivityManagerService,android中用來管理activity的java服務)會通過該管道請求Zygote fock()一個子進程。改子進程繼承zygote的記憶體區,從而直接用於zygote載入的類和資源。用這種方法,運行java應用的linux進程就避免了重複載入android基礎類和通用資源,從而極大的節省了時間開銷。

Dalvik vm 參考資料一文裡引用 【3】有對該過程形象的描述:

我們看到,所有應用(Maps, Browser, Home)都從 Zygote父進程那裡繼承了共用的庫。。

 

從以上描述可以猜測,dalvik啟動必然和zygote實現有關聯。的確是,dalvik虛擬機器執行個體啟動是zygote一手導致的。 本文將向你詳細展現這一過程。 但是,本文不打算直接用前面提到的順序跟蹤的方法展現從Zygote啟動dalvik虛擬機器執行個體的過程。相反,我們先採用反向追溯的方法。目的如下 1. 介紹反向追溯的使用 2. 加深對整個過程的印象。

從dalvik虛擬機器實現裡(dalvik/vm)我們看到有兩個檔案Init.h 和Init.cpp,從命名可以猜測出該檔案很可能和虛擬機器初始化有關係。初始化話肯定是指改啟動時完成的。開啟init.h,我們看到如下函數:

從命名來看,這很可能就是dalvik虛擬機器啟動和關閉的函數。 到Init.cpp裡我們可以看到他們的實現。雖然現在還不能完全看懂實現的細節,但可以肯定我們剛才對這兩個函數的判斷。

好,我們找到了虛擬機器初始化的啟動函數 dvmStartup()。由此,我們擁有了使用反向追溯的先決條件(一個後期的執行點)。根據這個點,我們就可以往前追溯出虛擬機器是如何被啟動的。 下面是簡單的流程說明:

1. 在代碼中全文檢索搜尋 改函數 dvmStartup()的使用。很幸運,只有一處真正的調用:

dalvik/vm/Jni.cpp                    3494 dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);

那麼啟動函數必然是從jni.cpp裡調用的,這也和改函數的注釋相符(“usually invoked through JNI”)

 

2. 到Jni.cpp裡看到,對dvmStartup()調用是在函數JNI_CreateJavaVM()裡完成的。繼續往前搜尋該函數的調用。 過濾掉該函數的聲明和定義,我們看到如下幾處調用:

frameworks/base/services/surfaceflinger/DdmConnection.cpp 

43 if (JNI_CreateJavaVM(&vm, &env, &args) == 0) {

 

dalvik/dalvikvm/Main.cpp 

212 if (JNI_CreateJavaVM(&vm, &env, &initArgs) < 0)
{

 

frameworks/base/core/jni/AndroidRuntime.cpp 

768 if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs)
< 0) {
769 LOGE("JNI_CreateJavaVM failed\n");

我們知道surfaceflinger是android中用於底層合成圖層的本地服務,不大可能作為所有虛擬機器執行個體啟動的起點。 另外兩個卻很有可能。

在前文 xxx (TODO),中我們提到, dalvik實現部署套件含兩個部分,dalvikvm可執行程式 和 libdvm共用庫。這個兩個調用正是對應了兩種調用啟動dalvik虛擬機器的方式的入口。可執行程式 dalvikvm在main.cpp中執行JNI_CreateJavaVM啟動虛擬機器執行個體,而其他的模組則通過 AndroidRuntime.cpp來啟動虛擬機器執行個體。

dalvikvm可執行程式我們在單獨的章節介紹,這裡我們來接續追溯普通情況下,邏輯是如何執行到AndroidRuntime.cpp裡啟動 虛擬機器執行個體的。

 

3. 進入AndroidRuntime.cpp我們看到,它是在 AndroidRuntime::startVm()裡調用的。繼續搜尋該函數的調用,只有一個,並且是同一檔案裡:

frameworks/base/core/jni/AndroidRuntime.cpp  464 int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) function
in class:android::AndroidRuntime
 
832 if (startVm(&mJavaVM, &env) != 0) {

 

 調用它的函數如下所示:

從該函數的注釋可以看出我們追蹤的方向是正確的。

 

4. 繼續往前,在全文檢索搜尋start時,我們得到巨量的搜尋結果。畢竟這個函數名字太常用了。 搜尋AndroidRuntime::start卻只有它的定義,這也難怪,該方法不是個類方法,使用時不會用AndroidRuntime::start(xxx)調用的。

那隻能先搜尋AndroidRuntime 和 start() 同時出現的使用類,並且只搜尋必須有 start。這樣子一下子是搜尋結果減少到小於十分之一,並且很容易判斷出是不是start函數調用。在結果中,我們一眼就看到了它:

 

frameworks/base/cmds/app_process/app_main.cpp 

15 #include <android_runtime/AndroidRuntime.h>
25 "Usage: app_process [java-options] cmd-dir start-class-name [options]\n");
28 class AppRuntime : public AndroidRuntime
68 * The easiest fix is to call FindClass here, early on before we start
88 AndroidRuntime* ar = AndroidRuntime::getRuntime();
108 AndroidRuntime::onExit(code);
169 } else if (strcmp(arg, "--start-system-server") == 0) {
189 runtime.start("com.android.internal.os.ZygoteInit",
190 startSystemServer ? "start

 這個檔案名稱字是不是很眼熟? 是的,前面我們講過,Zygote實現的原始碼起點正是這個檔案。

 

5. 展開改檔案對start的調用,發現是AppRuntime執行個體在調用改函數,不是AndroidRuntime! 找到AppRuntime實現,發現它是AndroidRuntime的子類,並且沒有它並沒有覆蓋start()方法,那麼它必然是調用了AndroidRuntime的start()方法了。 至此我們已經追溯到Zygote是如何啟動Dalvik虛擬機器執行個體的。

出於好奇,我們再看看,start啟動的類"com.android.internal.os.ZygoteInit"到底做什麼。它的源碼在 frameworks/base/core/java/com/android/internal/os/ZygoteInit.java 裡面。我們從它的視線裡看到了很多和前面介紹的Zygote與DVM互動的實現。比如註冊socket,載入基礎類以及資源等。

 

至此我們完全可以順序的勾勒出DVM執行個體啟動的全過程了:

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.