Android系統啟動流程
Android系統啟動流程
對於純Android應用層開發來講,瞭解一些Android的啟動流程的知識並不會直接提高自己的程式碼質量。但是作為整個Android系統的開端,這部分的流程時刻影響著應用層的方方面面。這些知識也是作為Android開發進階必須要了解的一部分。
過去你可能會有疑問,比如為什麼所有應用的父程序號都是同一個?ActivityManagerService是怎麼來的?Android上的Java虛擬機器什麼時候被載入的?
本文來分析總結一下Android 系統在啟動的Init、Zygote、SystemServer,來幫助大家瞭解一下。
一:Init
當用戶按下開機鍵的時候,引導晶片載入BootLoader到記憶體中,開始拉起Linux OS,一旦Linux核心啟動完畢後,它就會在系統檔案中尋找 <b>init.rc</b> 檔案,並啟動 <b>init</b> 程序。
什麼是 <b>init.rc</b> 檔案?
init.rc檔案是一個非常重要的配置檔案,它由AIL語言(Android Init Language)編寫。
(init.rc的一個小細節:Android8.0後對init.rc檔案進行了拆分,比如64位的Zygote的啟動指令碼在init.zygote64.rc檔案中)
在啟動的init程序中,會進入<b>system/core/init/init.cpp</b>檔案的main方法中,關鍵程式碼如下:
int main(int argc,char ** argv){ ... if(is_first_stage){ //建立和掛在啟動所需要的檔案目錄 mount("tmpfs","/dev","tmpfs",MS_NOSUID,"mode=0755"); mkdir("/dev/pts",0755); //建立和掛在很多... ... } ... //對屬性服務進行初始化 property_init(); ... //用於設定子程序訊號處理函式(如Zygote),如果子程序異常退出,init程序會呼叫該函式中設定的訊號處理函式來處理 signal_handler_init(); ... //啟動屬性服務 start_property_service(); ... //解析init.rc配置檔案 parser.ParseConfig("/init.rc"); }
上述程式碼中,有一個概念是 <b>屬性服務</b>,經常玩Windows 的同學應該知道WIndows登錄檔,登錄檔採用鍵值對的形式來記錄使用者、軟體的一些使用資訊,這樣即使系統或者軟體重啟也能夠根據之前登錄檔中的記錄來進行相應的初始化。init程序啟動的屬性服務,就是用來儲存這些屬性的。
屬性服務的查詢和修改都是通過Socket進行的,系統檔案內定義對多為8個使用者提供服務。並且屬性服務中的系統屬性分為兩種:普通屬性和控制屬性。控制屬性用來執行一些命令,比如開機的動畫就使用了這種屬性。
在處理了繁多的任務後,init程序會進行最關鍵的一部操作: <b>啟動Zygote</b>
程式碼在 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); } }
總結一下,init程序啟動後做了哪幾件事:
<b>(1)建立和掛在啟動所需要的檔案和目錄
(2)初始化和啟動屬性服務。
(3)解析init.rc配置檔案,並且啟動了Zygote程序</b>
二:Zygote
<b>(1)Zygote概述:
在Android系統中,DVM(Dalvik虛擬機器)和ART、應用程式程序以及執行系統關鍵服務的SystemServer程序都是由Zygote程序建立的,我們也將它稱為孵化器(本來字面意思就是受精卵...)。它通過fock複製程序的形勢來建立應用程序和SystemServer程序,由於Zygote程序在啟動時會建立DVM或者ART,因此通過fock而建立的應用程式程序和SystemServer程序可以在內部獲取一個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
<b>(2)Zygote啟動流程
Zygote啟動時主要呼叫app_main.cpp的main()中的AppRuntime的start方法來啟動Zygote程序。我們先展示app_main.cpp中的main函式。
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){ //如果當前程序在Zygote中,則設定zygote=true zygote=true; niceName=ZYGOTE_NICE_NAME; }else if(strcmp(arg,"--start-system-server")==0){ //如果當前程序在SystemServer中,將startSystemServer=true startSystemServer=true; } ... } ... //承接上面Init程序中的程式碼 if(zygote){ //啟動Zygote程序 runtime.start("com.android.internal.os.ZygoteInit",args,zygote); } }
由於Zygote程序都是通過fock自身來建立子程序,這樣Zygote程序和他的子程序(比如SystemServer)都可以進入app_main.cpp的main函式中,因此需要區分一下當前程序執行在哪個程序裡。
接下來我們進入 runtime.start中看看:
frameworks/base/core/jni/AndroidRuntime.cpp:
void AndroidRuntime::start(const char* className,const Vector<String8>& options,bool zygote){ ... //startVm函式用於啟動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呼叫ZygoteInit的main方法 env->CallStaticVoidMethod(startClass,startMeth,strArray); }
以上程式碼就厲害了,它從Init程序中的AndroidRuntime的main函式,啟動了Java虛擬機器,並且<b>通過JNI啟動了Zygote</b>,一波操作之後,Zygote順利從Native層進入了Java層。
隨後我們進入ZygoteInit中,看看它的main方法做了什麼。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java:
public static void main(String argv[]){ ... //建立一個Server端的Socket,socketName值為:zygote zygoteServer.registerServerSocket(socketName); if(!enableLazyPreload){ ... //預載入類和資源 preload(bootTimingsTraceLog); }else{ ... } if(startSystemServer){ //啟動SystemServer程序 startSystemServer(abiList,socketName,zygoteSerer); } //等待AMS的請求 zygoteServer.runSelectLoop(abiList); zygoteServer.closeServerSocket(); }
大致程式碼就此結束。
總結一下ZygoteInit的main方法都做了哪些事情:
<b>1.建立了一個Server端的Socket
2.預載入類和資源
3.啟動了SystemServer程序
4.等待AMS請求建立新的應用程式程序</b>
最後再總結一下Zygote程序啟動公做了幾件事:
<b>1.建立AndroidRuntime並呼叫其start方法,啟動Zygote程序。
2.建立Java虛擬機器併為Java虛擬機器註冊JNI方法。
3.通過JNI呼叫ZygoteInit的main函式進入Zygote的java框架層。
4.通過registerZygoteSocket方法建立服務端Socket,並通過runSelectLoop方法等待AMS的請求來建立新的應用程式程序。
5.啟動SystemServer。</b>
三:SystemServer
SystemServer程序主要用於建立系統服務,我們熟知的AMS、WMS、PMS都是由它來建立的。
在前面講到過,Zygote程序啟動了SystemServer程序,我們看一下啟動部分的程式碼。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java:
private static boolean startSystemServer(String abiList,String socketName){ ... //判斷程序是否是SystemServer if(pid == 0){ ... //關閉Zygote的Socket zygoteServer.closeServerSocket(); //啟動SystemServer程序 handleSystemServerProcess(parsedArgs); } }
由於SystemServer是Zygote程序fork出來的,所以該程序也擁有一個ZygoteServer所開啟等待AMS連線的Socket例項副本。在這裡並不需要這個Socket,所以關閉。
接下來看看handleSystemServerProcess()方法。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java:
private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs){ ... ClassLoader cl=null; if(systemServerClasspath!=null){ //在這裡建立了PathClassLoader cl = createPathClassLoader(systemServerClasspath,parsedArgs.targetSdkVersion); Thread.currentThread().setContextClassLoader(cl); } //zygoteInit方法 ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,parsedArgs.remainingArgs,cl); }
就是這裡,建立了大名鼎鼎的<b>PathClassLoader</b>。
接下來看看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(以及後來我們的應用程式程序的啟動)。
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}); ... //丟擲異常,這裡丟擲異常中呼叫了SystemServer的main方法 throw new Zygote.MethodAndArgsCaller(m,argv); }
在invokeStaticMain方法最後,以丟擲異常的方式呼叫了SystemServer的main方法(之後在啟動其他應用程序的時候,也是這樣呼叫ActivityThread的main方法的)。這種處理會清除所有設定過程需要的堆疊幀。
接下來我們解析一下SystemServer程序。
frameworks/base/services/java/com/android/server/SystemServer.java:
public static void main(String[] args){ //就一行程式碼 new SystemServer().run(); } private void run(){ ... //建立訊息Looper Looper.prepareMainLooper(); //載入動態庫 System.loadLibrary("android_servers"); //建立SystemServiceManager mSystemServiceManager=new SystemServiceManager(mSystemContext); ... //啟動引導服務 startBootstrapServices(); //啟動核心服務 startCoreServices(); //啟動其他服務 startOtherServices(); ... }
我們可以看到SystemServer在啟動後,陸續啟動了各項服務,包括ActivityManagerService,PowerManagerService,PackageManagerService等等,而這些服務的父類都是SystemService。
最後總結一下SystemServer程序:
<b>1.啟動Binder執行緒池
2.建立了SystemServiceManager(用於對系統服務進行建立、啟動和生命週期管理)
3.啟動了各種服務</b>
結尾
到此為止,本文基本結束了。Android系統啟動程式碼繁多,我們只截取了部分關鍵程式碼作為展示。最後總結一下,Init程序、Zygote、SystemServer的關係,如果還是有不懂的童鞋可以記住:
盤古(Linux 核心)開天闢地後,世上誕生了女媧(Init程序),女媧過於孤獨決定要個孩子,就用泥巴捏了個亞當(Zygote),後來亞當也覺得整天就跟他媽在一起也太煩了,決定造個女孩,於是用自己的肋骨(fork)建立了一個夏娃(SystemServer),於是萬物開始...
本文大量參考《Android 進階解密》一書,同時建議對Android底層有興趣的童鞋搞一本看看,裡面講解的必然比本文精闢不少。
本文純手打,歡迎各位點亮愛心,給個小小的贊以資鼓勵,謝謝