Android init進程之如何進入java世界
時間:2018-09-26 來源:未知
上一節(jié)我們了解了一下Android的init啟動流程,我們知道在init進程啟動的過程中,開啟 了很多服務。我們也知道Android上層的應用程序是用Java語言編寫的,Java語言編寫的 程序需要放在Java虛擬機中運行,為了提高Android App應用程序的效率,google公司提 供了經(jīng)過優(yōu)化之后的Dalvik虛擬機來運行上層Java語言編寫的程序。
好了,拋出兩個問題:
1、Android系統(tǒng)是如何從C/C++世界進入Java世界的呢?
2、Android系統(tǒng)是如何運行上層的APP應用程序的呢?
一、zygote進程介紹
回顧上一節(jié)我們知道init進程在啟動過程中啟動了一個叫做zygote服務。在Android 中,zygote是整個系統(tǒng)創(chuàng)建新進程的核心裝置。從字面上看,zygote是受精卵的意思,它 的主要工作就是進行細胞分裂。zygote進程內(nèi)部會先啟動Dalvik虛擬機,繼而加載一些必 要的系統(tǒng)資源和系統(tǒng)類,后進入一種監(jiān)聽狀態(tài)。在后續(xù)的運作中,當其他系統(tǒng)模塊(比 如AMS)希望創(chuàng)建新進程時,只需要向zygote進程發(fā)出請求,zygote進程監(jiān)聽到請求后, 會相應地"分裂"出新的進程,于是這個新進程在出生之時,就先天具有了自己的Dalvik 虛擬機及系統(tǒng)資源。

zygote服務在init.zygote32.rc文件中描述如下:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
init進程在運行app_process時根據(jù)如下規(guī)則傳遞參數(shù),app_process參數(shù)形式如下:
app_process [java-options] cmd-dir start-class-name [options]
(1)[java-options] : 傳遞給虛擬機的選項,必須以"-"開始
(2)cmd-dir : 所要運行的進程所在的目錄
(3)start-class-name : 要在虛擬機中運行的類的名稱。app_process會將制定的類加載到 虛擬機中,而后調(diào)用類的main()方法。
(4)[options] : 要傳遞給類的選項
根據(jù)參數(shù)規(guī)則,可以知道-Xzygote是指要傳遞給VM的選項。"-Xzygote"選項用來區(qū)分要 在虛擬機中運行的類是Zygote,還是在Zygote中運行其他Android應用程序,“--zygote”表示 加載com.android.internal.os.zygoteInit類。后一個參數(shù)"--start-system-server"作為選項傳 遞給生成的類,用于啟動運行系統(tǒng)服務器。
好了,了解完這些以后,我們來看看zygote的詳細實現(xiàn)。
二、zygote服務創(chuàng)建過程分析
通過前面的分析,我們知道zygote對應的應用程序是/system/bin/app_process,它對應的源 代碼在framework\base\cmds\app_process\app_main.cpp文件中。

可以看到在運行app_process應用程序的時候,傳遞了"--zygote"參數(shù),所以這里會調(diào)用到runtime.start("com.android.internal.os.ZygoteInit","args");這句話的含義是加載com.android.internal.os.ZygoteInit類運行。我們先來看 看runtime.start()函數(shù)的實現(xiàn)。

這段代碼主要用途如下如下:
(1)jni_invocation.Init(NULL)初始化jni接口
(2)startVM(&mJavaVM,&env)啟動Dalvik虛擬機
(3)startReg(env)注冊jni函數(shù)接口,方便Java世界與C/C++世界溝通
(4)FindClass(slashClassName)通過根據(jù)類名解析出來的路徑查找指定的類
(5)env->GetStaticMethodID()獲取指定指定類的main函數(shù)接口
(6)env->CallStaticVoidMethod()調(diào)用指定的函數(shù)接口
跋山涉水,終于構(gòu)造出了Java世界(AndroidRuntime---Dalvik虛擬機),接下來我們就開始在Java世界中加載第一個類:ZygoteInit運行。
三、ZygoteInit類運行過程分析
好了,至此我們從苦逼的C/C++世界進入了高富帥的Java世界,下面我們來看看 ZygoteInit類所做的事情,它對應的源代碼 在frameworks\base\core\java\com\android\internal\os\ZygoteInit.java中。

這段代碼的主要用途如下:
(1)registerZygoteSocket(socketName),這個函數(shù)用來綁定套接字,以便接收新Android應用 程序的運行請求。Zygote使用UDS(Unix Domain Socket),為了從接 收ActivityManagerService(AMS)發(fā)來的新Android應用程序的運行請求。
(2)preload()函數(shù)實現(xiàn)如下:
static void preload() {
Log.d(TAG, "begin preload"); preloadClasses(); //加載
preloadResources(); preloadOpenGL(); preloadSharedLibraries();
// Ask the WebViewFactory to do any initialization that must run in the zygote process,
// for memory sharing purposes. WebViewFactory.prepareWebViewInZygote(); Log.d(TAG, "end preload");
}
可以看到zygote進程在運行的過程中加載了應用程序框架中的類、平臺資源(圖像、 XML信息、字符串等)預先加載到內(nèi)存中。新進程直接使用這些類與資源,而不需要重 新加載他們,這大大加快了程序的執(zhí)行速度。
------------------------------------------------------------------------------------------------------------------------
加載應用程序Framework中包含的資源 在Android應用程序Framework中使用的字符串、顏色、圖像文件、音頻文件等都被 稱為資源。應用程序不能直接訪問這些資源,需要通過Android開發(fā)工具自動生成的 R類來訪問。通過R類可訪問的資源組成信息記錄在XML中。Android資源大致可以 分為兩大類,如下:
<1>Drawable 這類資源是指畫面、照片、圖標等可在畫面中繪畫的資源。preloadResource會加載 按鈕圖片、按鈕組等基本主題圖像。Android應用程序Framework中包含CheckBox、 Button、Editbox、Call等圖像文件。
<2>XML管理的資源
XML管理的資源有保存字符串的strings.xml、保存字符串數(shù)組的arrays.xml,以及保 存顏色值得colors.xml等。此外,動畫、布局等資源也是由XML文件管理的。
------------------------------------------------------------------------------------------------------------------------
(3)startSystemServer(abiList,socketName)

創(chuàng)建了一個子進程,然后在子進程中加載"com.android.server.SystemServer"類運行。下面 我們接著看看,它是如何運行SystemServer類運行的。

關(guān)閉了從父進程那邊繼承過來的套接字文件描述符,然手調(diào)用了RuntimInit.zygoteInit()方法。這個方法在frameworks\base\core\java\com\android\internal\os\RuntimeInit.java文件中定義,我們來看看它的具體實現(xiàn)

通過Class.forName加載SystemServer類,然后通過cl.getMethod()方法獲取SystemServer類 的main方法。 在這里我們并沒有看到直接調(diào)用這個"main"方法,而是拋出了一個一個異常。通過注釋 我們可以知道,這個異常
終會被ZygtoeInit.main()函數(shù)捕獲。

我們來看看caller.run()方法的實現(xiàn)。

很簡單啦,調(diào)用指定的方法。我們這里就是SystemServer類的main方法。嗯,至此SystemServer這個進程就創(chuàng)建 成功了。創(chuàng)建子進程成功后,我們的父進程zygote從startSystemServer()函數(shù)返回后,會 調(diào)用runSelectLoop()方法。

從注釋中我們就可以知道,zygote進程終一直在runSelectLoop函數(shù)工作。這個函數(shù) 終就會調(diào)用到C/C++層 的select函數(shù),探測socket文件描述附是否就緒。如果有,則說明ActivityManagerService向它發(fā)出了"啟動新應用進程" 的命令,zygote進程收到命令后,就會fork一個子進程,然后在子進程中拋出一個 MethodAndArgsCaller異常。 終會被ZygoteInit.main()函數(shù)捕獲,然后調(diào)用call.run()方法,終調(diào)用需要運行類 的main方法,這樣應用程序就跑起來啦。
好了,下面我們畫一幅圖總結(jié)一下zygote進程做的的事情:

四、SystemServer服務分析
通過前面的分析我們知道SystemServer是zygote進程孵化出來的第一個進程,它在 Android的運行環(huán)境中扮演了"神經(jīng)中樞"的作用,APK應用中能夠直接交互的大部分系統(tǒng) 服務都在該進程中運行,常見的比如WindowManagerServer(WMS)、 ActivityManagerSystemService(AMS)、PackageManagerServer(PMS)等,這些系統(tǒng)服務都是 以一個線程的方式存在于SystemServer進程中。所以SystemServer關(guān)系了整個Java世界 的生死存亡,如果SystemServer進程異常退出,zygote進程知道后就會"自殺",接著init 進程重新啟動zygote進程,從而再次開啟Java世界。
下面我們簡單分析一下SystemServer的運行過程:
frameworks\base\services\java\com\android\server\SystemServer.java

從上述代碼中我們可以看到SystemServer中啟動了Java世界中所需要的服務,它分為核心 平臺服務與硬件服務
(1)核心平臺服務(Core Platform Service) 一般而言,核心平臺服務不會直接與Android應用程序進行交互,但它們是Android Framework運行所必須的服務,其包含的主要服務如下表所示:

(2)硬件服務(Hardware Service)
該服務提供了一系列的API,用戶控制底層硬件, 主要服務包含如下

五、監(jiān)聽zygote socket分析

ZygoteInit的main()函數(shù)在調(diào)用完startSystemServer()之后,就會調(diào)用runSelectLoop()函數(shù), 它的代碼如下:
frameworks\base\core\java\com\android\internal\os\ZygoteInit.java

這段代碼完成的功能如下: (1)通過selectReadable()函數(shù)探測是否有連接請求
(2)如果有則調(diào)用acceptCommandPeer()函數(shù),提取添加請求,并且把已連接的文件描述符 添加到文件描述符集合中
(3)如果有zygote socket中有數(shù)據(jù)到達,則調(diào)用peers.get(index).runOnce()函數(shù)。
runOnce()函數(shù)的實現(xiàn)代碼如下: frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java:

這段代碼的功能如下: (1)調(diào)用Zygote.forkAndSpecialize()函數(shù)創(chuàng)建子進程 (2)調(diào)用handleChildProc()函數(shù)

可以看到這個函數(shù)終調(diào)用了ZygoteInit.invokeStaticMain()函數(shù),這個函數(shù)間接拋出特殊 的MethodAndArgsCaller異常,只不過此時拋出的異常攜帶的類名為ActivityThread。
注意:ActivityThread類在運行的時候,也標示著我們APK應用程序的運行,它就是 APK應用程序的入口哦!等等,Android APP應用程序的入口不是onCreate()方法嗎?呵呵!真正的入口是ActivityThread類, 這個類在運行的時候會間接調(diào)用到相應
類的onCreate()方法。


