Android原始碼學習之八—系統啟動過程
Android原始碼數量龐大,雖然對它的學習從未停止,但是整理成這樣的文字,實在是費時費力的一件事情,不過好在前文已經對其基本機制加以分析,相信以此為基礎,其他的內容學習起來就沒那麼困難了。
今天是2010年的最後一天了,回顧這一年,從手機作業系統的角度來看,我把重點放在了Android上,對Windows Phone和IPhone沒有太深入研究,正好以此做一終結,把對Android原始碼的學習告一段落。從軟體工程或專案管理角度來看,今年感觸也很多,可能會成為明年的重點吧,希望到時能在軟體工程方法、過程、架構設計、專案管理方面也能成些文字以供交流。
做為Android原始碼學習系列的最後一文,還是應該從大的角度寫點東西,想寫
Android的啟動過程可以分為兩個階段,第一階段是Linux的啟動,第二階段才是Android的啟動,下面我們分別來了解一下具體的過程。
首先是Linux啟動,這一部分我想就可以略過了,無非是Linux的Bootloader,Kernel,Driver之類的,在這裡唯一要提到的就是ServiceManager,即服務管理器,這個是做為一個程序在Android載入之前就被啟動了,我們可以從
service servicemanager /system/bin/servicemanager
ServiceManager是Binder的服務管理守護程序,是Binder的核心,由其使用Binder驅動進行IPC管理,關於IPC通訊的機制,此處不再詳述。在APP和Framework中,應用程式使用的ServiceManager.java就是通過Proxy與這個守護程序進行的通訊。
然後是Android的啟動,接下來要詳細描述的部分。我們還是先看一下init.rc中的配置
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
即linux啟動以後,啟動zygote服務程序,這個程序恰如其名:孵化器,是所有Android應用程式的孵化器。
我們來看一下app_process的程式碼,位置是在:
frameworks/base/cmds/app_process/app_main.cpp
在main()函式中有如下程式碼:
if (0 == strcmp("--zygote", arg)) {
bool startSystemServer = (i < argc) ?
strcmp(argv[i], "--start-system-server") == 0 : false;
setArgv0(argv0, "zygote");
set_process_name("zygote");
runtime.start("com.android.internal.os.ZygoteInit",
startSystemServer);
}
從中可以追蹤到AndroidRuntime,程式碼位於:
frameworks/base/core/jni/AndroidRuntime.cpp
在start()函式中有如下程式碼:
/* start the virtual machine */
if (startVm(&mJavaVM, &env) != 0)
goto bail;
……
env->CallStaticVoidMethod(startClass, startMeth, strArray);
即先啟動了虛擬機器,然後利用JNI呼叫了zygoteInit函式。
繼續追蹤到frameworks/base/core/java/com/android/internal/os/ZygoteInit.java的main()函式,程式碼如下:
if (argv[1].equals("true")) {
startSystemServer();
} else if (!argv[1].equals("false")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
Log.i(TAG, "Accepting command socket connections");
if (ZYGOTE_FORK_MODE) {
runForkMode();
} else {
runSelectLoopMode();
}
前一部分是在啟動系統服務,後一部分是雖然是一個條件判斷,但ZYGOTE_FORK_MODE被賦了false,所以進行else分支的runSelectLoopMode()函式,在該函式中,實際上是在一死迴圈中利用zygoteConnection類通過socket的方式進行訊息處理,用於fork出新的zygote,從而以最輕量級的方式實現每個程序一個虛擬機器的機制。
繼續來看startSystemServer(),程式碼位於:
frameworks/base/services/java/com/android/server/systemserver.java
在其main()函式中呼叫了init1(args)這個native函式,利用JNI機制,跟蹤至
frameworks/base/services/jni/com_android_server_systemService.cpp,然後到
frameworks/base/cmds/system_server/library/system_init.cpp
在system_init()函式中有如下程式碼:
if (strcmp(propBuf, "1") == 0) {
// Start the SurfaceFlinger
SurfaceFlinger::instantiate();
}
AndroidRuntime* runtime = AndroidRuntime::getRuntime();
LOGI("System server: starting Android services./n");
runtime->callStatic("com/android/server/SystemServer", "init2");
即完成了SurfaceFlinger的例項化,然後利用執行時的callStatic()函式呼叫了SystemServer的init2()函式,這個函式位於:
frameworks/base/services/java/com/android/server/SystemServer.java
程式碼是:
public static final void init2() {
Slog.i(TAG, "Entered the Android system server!");
Thread thr = new ServerThread();
thr.setName("android.server.ServerThread");
thr.start();
}
在這個ServerThread執行緒中,可以看到我們熟悉的Android服務了,比如WallpaperService服務的啟動:
try {
Slog.i(TAG, "Wallpaper Service");
wallpaper = new WallpaperManagerService(context);
ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
} catch (Throwable e) {
Slog.e(TAG, "Failure starting Wallpaper Service", e);
}
最後,呼叫各服務的systemReady()函式通知系統就緒。
至此,系統的啟動過程結束,借用兩張圖來說明問題:
從這裡可以看出,linux的init在啟動若干守護程序之後,就啟動了Android的runtime和zygote,zygote再啟動虛擬機器,系統服務,系統服務再啟動完本地服務後,又啟動了若干Android服務,並完成向ServiceManager的註冊工作,最後系統啟動完成。系統的程序空間如下圖所示:
可見,由zygote孵化器為各程序以寫時複製的方式用最小的代價實現了虛擬機器。
好了,相信經過這一系列的原始碼跟蹤,我們都能對Android的啟動過程有更清晰的認識,新年即將到來,在結束本系列文章的同時,祝大家新年快樂。