當(dāng)前位置:首頁(yè) > 嵌入式培訓(xùn) > 嵌入式學(xué)習(xí) > 講師博文 > Android init進(jìn)程之如何進(jìn)入java世界
上一節(jié)我們了解了一下Android的init啟動(dòng)流程,我們知道在init進(jìn)程啟動(dòng)的過程中,開啟 了很多服務(wù)。我們也知道Android上層的應(yīng)用程序是用Java語(yǔ)言編寫的,Java語(yǔ)言編寫的 程序需要放在Java虛擬機(jī)中運(yùn)行,為了提高Android App應(yīng)用程序的效率,google公司提 供了經(jīng)過優(yōu)化之后的Dalvik虛擬機(jī)來運(yùn)行上層Java語(yǔ)言編寫的程序。
好了,拋出兩個(gè)問題:
1、Android系統(tǒng)是如何從C/C++世界進(jìn)入Java世界的呢?
2、Android系統(tǒng)是如何運(yùn)行上層的APP應(yīng)用程序的呢?
一、zygote進(jìn)程介紹
回顧上一節(jié)我們知道init進(jìn)程在啟動(dòng)過程中啟動(dòng)了一個(gè)叫做zygote服務(wù)。在Android 中,zygote是整個(gè)系統(tǒng)創(chuàng)建新進(jìn)程的核心裝置。從字面上看,zygote是受精卵的意思,它 的主要工作就是進(jìn)行細(xì)胞分裂。zygote進(jìn)程內(nèi)部會(huì)先啟動(dòng)Dalvik虛擬機(jī),繼而加載一些必 要的系統(tǒng)資源和系統(tǒng)類,后進(jìn)入一種監(jiān)聽狀態(tài)。在后續(xù)的運(yùn)作中,當(dāng)其他系統(tǒng)模塊(比 如AMS)希望創(chuàng)建新進(jìn)程時(shí),只需要向zygote進(jìn)程發(fā)出請(qǐng)求,zygote進(jìn)程監(jiān)聽到請(qǐng)求后, 會(huì)相應(yīng)地"分裂"出新的進(jìn)程,于是這個(gè)新進(jìn)程在出生之時(shí),就先天具有了自己的Dalvik 虛擬機(jī)及系統(tǒng)資源。
zygote服務(wù)在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進(jìn)程在運(yùn)行app_process時(shí)根據(jù)如下規(guī)則傳遞參數(shù),app_process參數(shù)形式如下:
app_process [java-options] cmd-dir start-class-name [options]
(1)[java-options] : 傳遞給虛擬機(jī)的選項(xiàng),必須以"-"開始
(2)cmd-dir : 所要運(yùn)行的進(jìn)程所在的目錄
(3)start-class-name : 要在虛擬機(jī)中運(yùn)行的類的名稱。app_process會(huì)將制定的類加載到 虛擬機(jī)中,而后調(diào)用類的main()方法。
(4)[options] : 要傳遞給類的選項(xiàng)
根據(jù)參數(shù)規(guī)則,可以知道-Xzygote是指要傳遞給VM的選項(xiàng)。"-Xzygote"選項(xiàng)用來區(qū)分要 在虛擬機(jī)中運(yùn)行的類是Zygote,還是在Zygote中運(yùn)行其他Android應(yīng)用程序,“--zygote”表示 加載com.android.internal.os.zygoteInit類。后一個(gè)參數(shù)"--start-system-server"作為選項(xiàng)傳 遞給生成的類,用于啟動(dòng)運(yùn)行系統(tǒng)服務(wù)器。
好了,了解完這些以后,我們來看看zygote的詳細(xì)實(shí)現(xiàn)。
二、zygote服務(wù)創(chuàng)建過程分析
通過前面的分析,我們知道zygote對(duì)應(yīng)的應(yīng)用程序是/system/bin/app_process,它對(duì)應(yīng)的源 代碼在framework\base\cmds\app_process\app_main.cpp文件中。
可以看到在運(yùn)行app_process應(yīng)用程序的時(shí)候,傳遞了"--zygote"參數(shù),所以這里會(huì)調(diào)用到runtime.start("com.android.internal.os.ZygoteInit","args");這句話的含義是加載com.android.internal.os.ZygoteInit類運(yùn)行。我們先來看 看runtime.start()函數(shù)的實(shí)現(xiàn)。
這段代碼主要用途如下如下:
(1)jni_invocation.Init(NULL)初始化jni接口
(2)startVM(&mJavaVM,&env)啟動(dòng)Dalvik虛擬機(jī)
(3)startReg(env)注冊(cè)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虛擬機(jī)),接下來我們就開始在Java世界中加載第一個(gè)類:ZygoteInit運(yùn)行。
三、ZygoteInit類運(yùn)行過程分析
好了,至此我們從苦逼的C/C++世界進(jìn)入了高富帥的Java世界,下面我們來看看 ZygoteInit類所做的事情,它對(duì)應(yīng)的源代碼 在frameworks\base\core\java\com\android\internal\os\ZygoteInit.java中。
這段代碼的主要用途如下:
(1)registerZygoteSocket(socketName),這個(gè)函數(shù)用來綁定套接字,以便接收新Android應(yīng)用 程序的運(yùn)行請(qǐng)求。Zygote使用UDS(Unix Domain Socket),為了從接 收ActivityManagerService(AMS)發(fā)來的新Android應(yīng)用程序的運(yùn)行請(qǐng)求。
(2)preload()函數(shù)實(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進(jìn)程在運(yùn)行的過程中加載了應(yīng)用程序框架中的類、平臺(tái)資源(圖像、 XML信息、字符串等)預(yù)先加載到內(nèi)存中。新進(jìn)程直接使用這些類與資源,而不需要重 新加載他們,這大大加快了程序的執(zhí)行速度。
------------------------------------------------------------------------------------------------------------------------
加載應(yīng)用程序Framework中包含的資源 在Android應(yīng)用程序Framework中使用的字符串、顏色、圖像文件、音頻文件等都被 稱為資源。應(yīng)用程序不能直接訪問這些資源,需要通過Android開發(fā)工具自動(dòng)生成的 R類來訪問。通過R類可訪問的資源組成信息記錄在XML中。Android資源大致可以 分為兩大類,如下:
<1>Drawable 這類資源是指畫面、照片、圖標(biāo)等可在畫面中繪畫的資源。preloadResource會(huì)加載 按鈕圖片、按鈕組等基本主題圖像。Android應(yīng)用程序Framework中包含CheckBox、 Button、Editbox、Call等圖像文件。
<2>XML管理的資源
XML管理的資源有保存字符串的strings.xml、保存字符串?dāng)?shù)組的arrays.xml,以及保 存顏色值得colors.xml等。此外,動(dòng)畫、布局等資源也是由XML文件管理的。
------------------------------------------------------------------------------------------------------------------------
(3)startSystemServer(abiList,socketName)
創(chuàng)建了一個(gè)子進(jìn)程,然后在子進(jìn)程中加載"com.android.server.SystemServer"類運(yùn)行。下面 我們接著看看,它是如何運(yùn)行SystemServer類運(yùn)行的。
關(guān)閉了從父進(jìn)程那邊繼承過來的套接字文件描述符,然手調(diào)用了RuntimInit.zygoteInit()方法。這個(gè)方法在frameworks\base\core\java\com\android\internal\os\RuntimeInit.java文件中定義,我們來看看它的具體實(shí)現(xiàn)
通過Class.forName加載SystemServer類,然后通過cl.getMethod()方法獲取SystemServer類 的main方法。 在這里我們并沒有看到直接調(diào)用這個(gè)"main"方法,而是拋出了一個(gè)一個(gè)異常。通過注釋 我們可以知道,這個(gè)異常
終會(huì)被ZygtoeInit.main()函數(shù)捕獲。
我們來看看caller.run()方法的實(shí)現(xiàn)。
很簡(jiǎn)單啦,調(diào)用指定的方法。我們這里就是SystemServer類的main方法。嗯,至此SystemServer這個(gè)進(jìn)程就創(chuàng)建 成功了。創(chuàng)建子進(jìn)程成功后,我們的父進(jìn)程zygote從startSystemServer()函數(shù)返回后,會(huì) 調(diào)用runSelectLoop()方法。
從注釋中我們就可以知道,zygote進(jìn)程終一直在runSelectLoop函數(shù)工作。這個(gè)函數(shù) 終就會(huì)調(diào)用到C/C++層 的select函數(shù),探測(cè)socket文件描述附是否就緒。如果有,則說明ActivityManagerService向它發(fā)出了"啟動(dòng)新應(yīng)用進(jìn)程" 的命令,zygote進(jìn)程收到命令后,就會(huì)fork一個(gè)子進(jìn)程,然后在子進(jìn)程中拋出一個(gè) MethodAndArgsCaller異常。 終會(huì)被ZygoteInit.main()函數(shù)捕獲,然后調(diào)用call.run()方法,終調(diào)用需要運(yùn)行類 的main方法,這樣應(yīng)用程序就跑起來啦。
好了,下面我們畫一幅圖總結(jié)一下zygote進(jìn)程做的的事情:
四、SystemServer服務(wù)分析
通過前面的分析我們知道SystemServer是zygote進(jìn)程孵化出來的第一個(gè)進(jìn)程,它在 Android的運(yùn)行環(huán)境中扮演了"神經(jīng)中樞"的作用,APK應(yīng)用中能夠直接交互的大部分系統(tǒng) 服務(wù)都在該進(jìn)程中運(yùn)行,常見的比如WindowManagerServer(WMS)、 ActivityManagerSystemService(AMS)、PackageManagerServer(PMS)等,這些系統(tǒng)服務(wù)都是 以一個(gè)線程的方式存在于SystemServer進(jìn)程中。所以SystemServer關(guān)系了整個(gè)Java世界 的生死存亡,如果SystemServer進(jìn)程異常退出,zygote進(jìn)程知道后就會(huì)"自殺",接著init 進(jìn)程重新啟動(dòng)zygote進(jìn)程,從而再次開啟Java世界。
下面我們簡(jiǎn)單分析一下SystemServer的運(yùn)行過程:
frameworks\base\services\java\com\android\server\SystemServer.java
從上述代碼中我們可以看到SystemServer中啟動(dòng)了Java世界中所需要的服務(wù),它分為核心 平臺(tái)服務(wù)與硬件服務(wù)
(1)核心平臺(tái)服務(wù)(Core Platform Service) 一般而言,核心平臺(tái)服務(wù)不會(huì)直接與Android應(yīng)用程序進(jìn)行交互,但它們是Android Framework運(yùn)行所必須的服務(wù),其包含的主要服務(wù)如下表所示:
(2)硬件服務(wù)(Hardware Service)
該服務(wù)提供了一系列的API,用戶控制底層硬件, 主要服務(wù)包含如下
五、監(jiān)聽zygote socket分析
ZygoteInit的main()函數(shù)在調(diào)用完startSystemServer()之后,就會(huì)調(diào)用runSelectLoop()函數(shù), 它的代碼如下:
frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
這段代碼完成的功能如下: (1)通過selectReadable()函數(shù)探測(cè)是否有連接請(qǐng)求
(2)如果有則調(diào)用acceptCommandPeer()函數(shù),提取添加請(qǐng)求,并且把已連接的文件描述符 添加到文件描述符集合中
(3)如果有zygote socket中有數(shù)據(jù)到達(dá),則調(diào)用peers.get(index).runOnce()函數(shù)。
runOnce()函數(shù)的實(shí)現(xiàn)代碼如下: frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java:
這段代碼的功能如下: (1)調(diào)用Zygote.forkAndSpecialize()函數(shù)創(chuàng)建子進(jìn)程 (2)調(diào)用handleChildProc()函數(shù)
可以看到這個(gè)函數(shù)終調(diào)用了ZygoteInit.invokeStaticMain()函數(shù),這個(gè)函數(shù)間接拋出特殊 的MethodAndArgsCaller異常,只不過此時(shí)拋出的異常攜帶的類名為ActivityThread。
注意:ActivityThread類在運(yùn)行的時(shí)候,也標(biāo)示著我們APK應(yīng)用程序的運(yùn)行,它就是 APK應(yīng)用程序的入口哦!等等,Android APP應(yīng)用程序的入口不是onCreate()方法嗎?呵呵!真正的入口是ActivityThread類, 這個(gè)類在運(yùn)行的時(shí)候會(huì)間接調(diào)用到相應(yīng)
類的onCreate()方法。