Android系統(tǒng)啟動流程
對于純Android應(yīng)用層開發(fā)來講汁尺,了解一些Android的啟動流程的知識并不會直接提高自己的代碼質(zhì)量屋讶。但是作為整個Android系統(tǒng)的開端悴能,這部分的流程時刻影響著應(yīng)用層的方方面面窃躲。這些知識也是作為Android開發(fā)進階必須要了解的一部分嫂伞。
過去你可能會有疑問方椎,比如為什么所有應(yīng)用的父進程號都是同一個聂抢?ActivityManagerService是怎么來的?Android上的Java虛擬機什么時候被加載的辩尊?
本文來分析總結(jié)一下Android 系統(tǒng)在啟動的Init涛浙、Zygote、SystemServer摄欲,來幫助大家了解一下轿亮。
一:Init
當(dāng)用戶按下開機鍵的時候,引導(dǎo)芯片加載BootLoader到內(nèi)存中胸墙,開始拉起Linux OS我注,一旦Linux內(nèi)核啟動完畢后,它就會在系統(tǒng)文件中尋找 init.rc 文件迟隅,并啟動init 進程但骨。
什么是 init.rc 文件励七?
init.rc文件是一個非常重要的配置文件,它由AIL語言(Android Init Language)編寫奔缠。
(init.rc的一個小細(xì)節(jié):Android8.0后對init.rc文件進行了拆分掠抬,比如64位的Zygote的啟動腳本在init.zygote64.rc文件中)
在啟動的init進程中,會進入system/core/init/init.cpp文件的main方法中校哎,關(guān)鍵代碼如下:
int main(int argc,char ** argv){
...
if(is_first_stage){
//創(chuàng)建和掛在啟動所需要的文件目錄
mount("tmpfs","/dev","tmpfs",MS_NOSUID,"mode=0755");
mkdir("/dev/pts",0755);
//創(chuàng)建和掛在很多...
...
}
...
//對屬性服務(wù)進行初始化
property_init();
...
//用于設(shè)置子進程信號處理函數(shù)(如Zygote)两波,如果子進程異常退出,init進程會調(diào)用該函數(shù)中設(shè)定的信號處理函數(shù)來處理
signal_handler_init();
...
//啟動屬性服務(wù)
start_property_service();
...
//解析init.rc配置文件
parser.ParseConfig("/init.rc");
}
上述代碼中,有一個概念是 屬性服務(wù),經(jīng)常玩Windows 的同學(xué)應(yīng)該知道WIndows注冊表,注冊表采用鍵值對的形式來記錄用戶轻绞、軟件的一些使用信息,這樣即使系統(tǒng)或者軟件重啟也能夠根據(jù)之前注冊表中的記錄來進行相應(yīng)的初始化劣坊。init進程啟動的屬性服務(wù),就是用來儲存這些屬性的屈留。
屬性服務(wù)的查詢和修改都是通過Socket進行的局冰,系統(tǒng)文件內(nèi)定義對多為8個用戶提供服務(wù)。并且屬性服務(wù)中的系統(tǒng)屬性分為兩種:普通屬性和控制屬性绕沈∪裣耄控制屬性用來執(zhí)行一些命令帮寻,比如開機的動畫就使用了這種屬性乍狐。
在處理了繁多的任務(wù)后,init進程會進行最關(guān)鍵的一部操作: 啟動Zygote
代碼在 frameworks/base/cmds/app_process/app_main.cpp中:
int main(int argc ,char* const argv[]){
...
if(zygote){
//啟動Zygote進程
runtime.start("com.android.internal.os.ZygoteInit",args,zygote);
}
}
總結(jié)一下固逗,init進程啟動后做了哪幾件事:
(1)創(chuàng)建和掛載啟動所需要的文件和目錄
(2)初始化和啟動屬性服務(wù)浅蚪。
(3)解析init.rc配置文件,并且啟動了Zygote進程
二:Zygote
(1)Zygote概述:
在Android系統(tǒng)中烫罩,DVM(Dalvik虛擬機)和ART惜傲、應(yīng)用程序進程以及運行系統(tǒng)關(guān)鍵服務(wù)的SystemServer進程都是由Zygote進程創(chuàng)建的,我們也將它稱為孵化器(本來字面意思就是受精卵...)贝攒。它通過fork復(fù)制進程的形勢來創(chuàng)建應(yīng)用進程和SystemServer進程盗誊,由于Zygote進程在啟動時會創(chuàng)建DVM或者ART,因此通過fork而創(chuàng)建的應(yīng)用程序進程和SystemServer進程可以在內(nèi)部獲取一個DVM或者ART的實例副本隘弊。
init.rc文件引入Zygote的啟動腳本哈踱,這些腳本都是由AIL編寫的。
由于Android 5.0后,Android開始支持64位程序梨熙,Zygote也就有了32位與64位之分开镣。一共有四種Zygote啟動腳本:
init.zygote32.rc
init.zygote32_64.rc
init.zygote64.rc
init.zygote64_32.rc
(2)Zygote啟動流程
Zygote啟動時主要調(diào)用app_main.cpp的main()中的AppRuntime的start方法來啟動Zygote進程。我們先展示app_main.cpp中的main函數(shù)咽扇。
frameworks/base/cmds/app_process/app_main.cpp:
int main(int argc,char* const argv[]){
...
while( i < argc ){
const char* arg=argv[i++];
if(strcmp(arg,"--zygote")==0){
//如果當(dāng)前進程在Zygote中邪财,則設(shè)置zygote=true
zygote=true;
niceName=ZYGOTE_NICE_NAME;
}else if(strcmp(arg,"--start-system-server")==0){
//如果當(dāng)前進程在SystemServer中陕壹,將startSystemServer=true
startSystemServer=true;
}
...
}
...
//承接上面Init進程中的代碼
if(zygote){
//啟動Zygote進程
runtime.start("com.android.internal.os.ZygoteInit",args,zygote);
}
}
由于Zygote進程都是通過fock自身來創(chuàng)建子進程,這樣Zygote進程和他的子進程(比如SystemServer)都可以進入app_main.cpp的main函數(shù)中树埠,因此需要區(qū)分一下當(dāng)前進程運行在哪個進程里糠馆。
接下來我們進入 runtime.start中看看:
frameworks/base/core/jni/AndroidRuntime.cpp:
void AndroidRuntime::start(const char* className,const Vector<String8>& options,bool zygote){
...
//startVm函數(shù)用于啟動Java虛擬機
if(startVm(&mJavaVM,&env,zygote)!=0){
return;
}
onVmCreated(env);
//為Java虛擬機注冊JNI方法
if(startReg(env)<0){
return;
}
...
//從app_main的main方法中得知,className是com.android.internal.os.ZygoteInit
classNameStr=env->NewStringUTF(className);
...
//找到ZygoteInit類
jclass startClass=env->FindClass(slashClassName);
...
//找到ZygoteInit的main方法
jmethodID startMeth=env->GetStaticMethodID(startClass,"main","([Ljava/lang/String;)V");
...
//通過JNI調(diào)用ZygoteInit的main方法
env->CallStaticVoidMethod(startClass,startMeth,strArray);
}
以上代碼就厲害了怎憋,它從Init進程中的AndroidRuntime的main函數(shù)榨惠,啟動了Java虛擬機,并且通過JNI啟動了Zygote盛霎,一波操作之后赠橙,Zygote順利從Native層進入了Java層。
隨后我們進入ZygoteInit中愤炸,看看它的main方法做了什么期揪。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java:
public static void main(String argv[]){
...
//創(chuàng)建一個Server端的Socket,socketName值為:zygote
zygoteServer.registerServerSocket(socketName);
if(!enableLazyPreload){
...
//預(yù)加載類和資源
preload(bootTimingsTraceLog);
}else{
...
}
if(startSystemServer){
//啟動SystemServer進程
startSystemServer(abiList,socketName,zygoteSerer);
}
//等待AMS的請求
zygoteServer.runSelectLoop(abiList);
zygoteServer.closeServerSocket();
}
大致代碼就此結(jié)束规个。
總結(jié)一下ZygoteInit的main方法都做了哪些事情:
**1.創(chuàng)建了一個Server端的Socket(名為zygote凤薛,AndroidQ之后改為在ZygoteServer的構(gòu)造中創(chuàng)建該Socket,以及USAPSocket)
ZygoteServer(boolean isPrimaryZygote) {
mUsapPoolEventFD = Zygote.getUsapPoolEventFD();
if (isPrimaryZygote) {
mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
mUsapPoolSocket =
Zygote.createManagedSocketFromInitSocket(
Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
} else {
mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);
mUsapPoolSocket =
Zygote.createManagedSocketFromInitSocket(
Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);
}
mUsapPoolSupported = true;
fetchUsapPoolPolicyProps();
}
2.預(yù)加載類和資源
3.啟動了SystemServer進程
4.等待AMS請求創(chuàng)建新的應(yīng)用程序進程**
最后再總結(jié)一下Zygote進程啟動公做了幾件事:
1.創(chuàng)建AndroidRuntime并調(diào)用其start方法诞仓,啟動Zygote進程缤苫。
2.創(chuàng)建Java虛擬機并為Java虛擬機注冊JNI方法。
3.通過JNI調(diào)用ZygoteInit的main函數(shù)進入Zygote的java框架層墅拭。
4.通過registerZygoteSocket方法創(chuàng)建服務(wù)端Socket活玲,并通過runSelectLoop方法等待AMS的請求來創(chuàng)建新的應(yīng)用程序進程。
5.啟動SystemServer谍婉。
三:SystemServer
SystemServer進程主要用于創(chuàng)建系統(tǒng)服務(wù)舒憾,我們熟知的AMS、WMS穗熬、PMS都是由它來創(chuàng)建的镀迂。
在前面講到過,Zygote進程啟動了SystemServer進程唤蔗,我們看一下啟動部分的代碼探遵。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java:
private static boolean startSystemServer(String abiList,String socketName){
...
//判斷進程是否是SystemServer
if(pid == 0){
...
//關(guān)閉Zygote的Socket
zygoteServer.closeServerSocket();
//啟動SystemServer進程
handleSystemServerProcess(parsedArgs);
}
}
由于SystemServer是Zygote進程fork出來的,所以該進程也擁有一個ZygoteServer所開啟等待AMS連接的Socket實例副本妓柜。在這里并不需要這個Socket箱季,所以關(guān)閉。
接下來看看handleSystemServerProcess()方法领虹。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java:
private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs){
...
ClassLoader cl=null;
if(systemServerClasspath!=null){
//在這里創(chuàng)建了PathClassLoader
cl = createPathClassLoader(systemServerClasspath,parsedArgs.targetSdkVersion);
Thread.currentThread().setContextClassLoader(cl);
}
//zygoteInit方法
ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,parsedArgs.remainingArgs,cl);
}
就是這里规哪,創(chuàng)建了大名鼎鼎的 PathClassLoader。
接下來看看zygoteInit方法塌衰。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java:
public static final void zygoteInit(int targetSdkVersion,String[] argv,ClassLoader classLoader){
...
//就在該方法中诉稍,啟動了Binder線程池
ZygoteInit.nativeZygoteInit();
//進入SystemServer的main方法
RuntimeInit.applicationInit(targetSdkVersion,argv,classLoader);
}
nativeZygoteInit方法一看名稱蝠嘉,就知道是在Native層的代碼。用來啟動Binder線程池杯巨,這樣SystemServer進程就可以使用Binder與其他進程進行通信了蚤告。
再講一下RuntimeInit的applicationInit方法,該方法用于啟動SystemServer(以及后來我們的應(yīng)用程序進程的啟動)服爷。
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java:
protected static void applicationINit(int targetSdkVersion,String[] argv,ClassLoader classLoader){
...
invokeStaticMain(args.startClass,args.startArgs,classLoader);
}
...
private static void invokeStaticMain(String className,String[] argv,ClassLoader classLoader){
Class<?> cl;
...
//className是com.android.server.SystemServer
cl=Class.forName(className,true,classLoader);
...
//找到SystemServer的main方法
m=cl.getMethod("main",new Class[]{String[].class});
...
//拋出異常杜恰,這里拋出異常中調(diào)用了SystemServer的main方法
throw new Zygote.MethodAndArgsCaller(m,argv);
}
在invokeStaticMain方法最后,以拋出異常的方式調(diào)用了SystemServer的main方法(之后在啟動其他應(yīng)用進程的時候仍源,也是這樣調(diào)用ActivityThread的main方法的)心褐。這種處理會清除所有設(shè)置過程需要的堆棧幀。
接下來我們解析一下SystemServer進程笼踩。
frameworks/base/services/java/com/android/server/SystemServer.java:
public static void main(String[] args){
//就一行代碼
new SystemServer().run();
}
private void run(){
...
//創(chuàng)建消息Looper
Looper.prepareMainLooper();
//加載動態(tài)庫
System.loadLibrary("android_servers");
//創(chuàng)建SystemServiceManager
mSystemServiceManager=new SystemServiceManager(mSystemContext);
...
//啟動引導(dǎo)服務(wù)
startBootstrapServices();
//啟動核心服務(wù)
startCoreServices();
//啟動其他服務(wù)
startOtherServices();
...
}
我們可以看到SystemServer在啟動后逗爹,陸續(xù)啟動了各項服務(wù),包括ActivityManagerService嚎于,PowerManagerService掘而,PackageManagerService等等,而這些服務(wù)的父類都是SystemService于购。
最后總結(jié)一下SystemServer進程:
1.啟動Binder線程池
2.創(chuàng)建了SystemServiceManager(用于對系統(tǒng)服務(wù)進行創(chuàng)建袍睡、啟動和生命周期管理)
3.啟動了各種服務(wù)
結(jié)尾
到此為止,本文基本結(jié)束了肋僧。Android系統(tǒng)啟動代碼繁多斑胜,我們只截取了部分關(guān)鍵代碼作為展示。最后總結(jié)一下色瘩,Init進程伪窖、Zygote、SystemServer的關(guān)系居兆,如果還是有不懂的童鞋可以記住:
盤古(Linux 內(nèi)核)開天辟地后竹伸,世上誕生了女媧(Init進程)泥栖,女媧過于孤獨決定要個孩子,就用泥巴捏了個亞當(dāng)(Zygote)勋篓,后來亞當(dāng)也覺得整天就跟他媽在一起也太煩了吧享,決定造個女孩,于是用自己的肋骨(fork)創(chuàng)建了一個夏娃(SystemServer)譬嚣,于是萬物開始...
本文大量參考《Android 進階解密》一書钢颂,同時建議對Android底層有興趣的童鞋搞一本看看,里面講解的必然比本文精辟不少拜银。
本文純手打殊鞭,歡迎各位點亮愛心遭垛,給個小小的贊以資鼓勵,謝謝