概述
Android系統
是基于Linux的,啟動必須經歷3個階段,即:Boot Loader
,Linux Kernel
,Android系統服務
,筆者今天就基于Android 8.1 系統源代碼來分析一下啟動過程
。
大家本地如果沒有源代碼的可以在線查看:
https://www.androidos.net.cn/sourcecode
啟動流程圖
下面是筆者根據一些博客以及系統源代碼對比整理出來的一張流程圖,由于整個過程涉及到的模塊很多,目前只是整理了大致的模塊流程,具體的細節后續會逐步整理說明。
本文設計到的幾個關鍵類
及路徑
關鍵類 | 路徑 |
---|---|
init.rc | system/core/rootdir/init.rc |
init.cpp | system/core/init/init.cpp |
init.zygote64.rc | system/core/rootdir/init.zygote64.rc |
app_main.cpp | frameworks/base/cmds/app_process/app_main.cpp |
AndroidRuntime.cpp | frameworks/base/core/jni/AndroidRuntime.cpp |
ZygoteInit.java | frameworks/base/core/java/com/android/internal/os/ZygoteInit.java |
ZygoteServer.java | frameworks/base/core/java/com/android/internal/os/ZygoteServer.java |
Android系統啟動必經的三個步驟:
1. 按下電源系統啟動
當電源按下時引導芯片代碼開始從預定義的地方(固化在ROM)開始執行,加載引導程序
Bootloader
到RAM
,然后執行。
2. 引導程序Bootloader
引導程序是在Android操作系統開始運行前的一個小程序,它的主要作用是把系統OS拉起來并運行。
3. linux內核啟動
內核啟動時,設置緩存、被保護存儲器、計劃列表,加載驅動。當內核完成系統設置,它首先在系統文件中尋找
"init"
文件,然后啟動root進程
或者系統的第一個進程
。
第一個進程:init進程
作為Android系統
中第一個被啟動的進程,init進程的PID為0
,它會通過解析init.rc腳本
來構建系統的初始形態。
一個完整的init.rc腳本
通常由4種類型的聲明組成,即:
Action(動作):
on <trigger> ##觸發條件
<command1> ##執行命令
<command2> ##執行多個命令
...
一個Action
實際是響應某一個事件的過程,即當<trigger>
所描述的觸發事件產生時,依次執行各種command(可以執行多個對應的命令)
。
Commands(命令):
命令會將所屬事件被一個一個執行
Services(服務):
service <name><pathname> [ <argument> ]*
<option>
<option>
...
<name>
表示service
的名稱
<pathname>
表示可執行文件的路徑
<argument>
啟動service
所帶的參數
<option>
對此service
的約束選項
Options(選項)
約束選項
Android中的DNS服務器
——ServiceManager
ServiceManager
可以理解為Binder機制中
的DNS服務器
,負責某Binder服務在ServiceManager注冊時提供的名稱
到底層Binder驅動分配的值
的解析。
servicemanager
是在system/core/rootdir/init.rc
描述并由init進程
啟動的。
on post-fs
......
load_system_props
# start essential services
start logd
//啟動servicemanager
start servicemanager
start hwservicemanager
start vndservicemanager
這是frameworks/native/cmds/servicemanager.rc
描述腳本
service servicemanager /system/bin/servicemanager
class core animation
user system
group system readproc
critical
onrestart restart healthd
onrestart restart zygote
onrestart restart audioserver
onrestart restart media
onrestart restart surfaceflinger
onrestart restart inputflinger
onrestart restart drm
onrestart restart cameraserver
writepid /dev/cpuset/system-background/tasks
shutdown critical
Zygote進程
在Android中,Zygote
是整個系統創建新進程的核心進程。和ServiceManager類似
,它也是由init進程
解析init.rc腳本
時啟動的。
由于系統不斷升級,Android系統也不得不面對32位和64位機器同時存在的情況,所以Zygote
的啟動也需要根據不同的情況進行區分:
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc
......
Zygote進程
在內部會先啟動虛擬機
,繼而加載一些必要的系統資源和系統類
,最后進入一種監聽狀態。在之后的運作中,當其他系統模塊(比如 AMS)
希望創建新進程時,只需向Zygote進程
發出請求,Zygote進程
監聽到該請求后,會相應地fork出新的進程
,于是這個新進程在初生之時,就先天具有了自己的虛擬機以及系統資源
。
下面是不同的描述Zygote
的rc腳本
腳本 | 描述 |
---|---|
init.zygote32.rc |
zygote進程 對應的執行程序是app_process (純32位模式) |
init.zygote64.rc |
zygote進程 對應的執行程序是app_process64 (純64位模式) |
init.zygote32_64.rc | 啟動兩個zygote進程 (名為zygote和zygote_secondary ),對應的執行程序分別是 app_process32 (主模式)、app_process64
|
init.zygote64_32.rc | 啟動兩個zygote進程 (名為zygote和zygote_secondary ),對應的執行程序分別是 app_process64 (主模式)、app_process32
|
這里以64位機器為例:/system/core/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
上述腳本內容我們可以看到,啟動的是一個名為Zygote的進程
,對應的程序名為:app_process64
在frameworks/base/cmds/app_process
目錄下,我們找到Android.mk文件
:
LOCAL_PATH:= $(call my-dir)
app_process_common_shared_libs := \
libandroid_runtime \
libbinder \
libcutils \
libdl \
libhwbinder \
liblog \
libnativeloader \
libutils \
......
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= $(app_process_src_files)
LOCAL_LDFLAGS_32 := $(app_process_ldflags_32)
LOCAL_LDFLAGS_64 := $(app_process_ldflags_64)
LOCAL_SHARED_LIBRARIES := $(app_process_common_shared_libs)
LOCAL_WHOLE_STATIC_LIBRARIES := $(app_process_common_static_libs)
LOCAL_MODULE:= app_process
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64
LOCAL_CFLAGS += $(app_process_cflags)
......
include $(BUILD_EXECUTABLE)
上述腳本決定了最終編譯出來的目標文件
下面我們來看看frameworks/base/cmds/app_process/app_main.cpp
中main函數
的部分關鍵代碼:
int main(int argc, char* const argv[])
{
.....
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
......
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
}
}
上面的函數用來解析啟動app_process
時傳入的參數:
--zygote:指明以ZygoteInit.java類中的main函數作為虛擬機執行入口
--start-system-server:告訴Zygote進程啟動SystemServer進程
注意上述的AppRuntime本身是繼承自AndroidRuntime的
,因此最終實際調用的還是AndroidRuntime中的start函數
虛擬機的啟動
在上面的Zygote啟動
中也看到了虛擬機的啟動
代碼了
下面來看看frameworks/base/core/jni/AndroidRuntime.cpp
中main函數
的實現:
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
//初始化JNI環境
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
//啟動虛擬機
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
//虛擬機啟動后回調
onVmCreated(env);
// 注冊JNI函數
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
......
char* slashClassName = toSlashClassName(className != NULL ? className : "");
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
......
} else {
//通過反射找到ZygoteInit的main函數
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
......
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
}
}
free(slashClassName);
......
上面的過程其實就是啟動虛擬機
的過程,這里由于篇幅關系,并不大算深究每一個模塊,而是先粗看整體的框架結構。虛擬機啟動完成之后,會通過反射的形式
調用frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
中的main方法
:
ZygoteServer zygoteServer = new ZygoteServer();
......
try {
......
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
//啟動SystemServer
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
//注冊服務端的Socket
zygoteServer.registerServerSocket(socketName);
......
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
//預加載各類資源
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
}
......
if (startSystemServer) {
//正式啟動SystemServer
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
......
if (r != null) {
r.run();
return;
}
}
......
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
zygoteServer.closeServerSocket();
}
因此在ZygoteInit中比較關鍵的兩個操作:
1.注冊一個Socket
:如果由新進程需要創建,系統會通過這個Socket
來通知它完成進程孵化工作
。
2.預加載各類資源:
主要用來預加載虛擬機所需要的各類資源。
緊接著就是下面的代碼:
runSelectLoop(abiList);
這段代碼的內部實現其實就是一個while死循環
,它用來作為Zygote的守護進程
啟動SystemServer
前面的ServiceManager
,Zygote
,虛擬機
等啟動過程有了一定的了解了,下面就是關鍵的SystemServer啟動
了,之前的腳本也看到了一個叫--start-system-server
的參數,這個就是用來啟動SystemServer
的。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
中
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
......
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
//子進程
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket();
//啟動各個System Server進程
return handleSystemServerProcess(parsedArgs);
}
return null;
}
在ZygoteInit中
通過forkSystemServer方法
創建了一個新進程,這個新進程(pid==0)
會在隨后的過程中通過handleSystemServerProcess
來啟動各種支撐系統運行的System Server
小結
在Android系統
中,每個進程都運行在對應的虛擬機上,因此Zygote
首先就負責創建出虛擬機
。
然后,為了反射調用java代碼,必須有對應的JNI函數
,于是Zygote
進行了JNI函數的注冊
。
當一切準備妥當后,Zygote進程
才進入到了java的世界
。
參考:
《深入理解Android內核設計思想》
https://blog.csdn.net/freekiteyu/article/details/79175010
https://www.cnblogs.com/pepsimaxin/p/9443002.html
https://www.cnblogs.com/pepsimaxin/p/9448874.html
https://www.cnblogs.com/tiantianbyconan/p/5013863.html