Android 6.0 系統學習之 Zygote
一次看到 Zygote 時,不明白這個名字什么意思,查了一下發現是受精卵的意思。Zygote 是 Android 系統中啟動應用程序與系統服務的服務。
學習 Zygote 這個服務,我想弄明白這些問題:
- Zygote 自己是由誰啟動的?
- Zygote 都能啟動哪些東西?
- Zygote 是如何啟動其他程序、服務的? </ol>
- 關鍵字 service 表示告訴 init 進程創建名為 zygote 的進程,所要執行的程序是 /system/bin/app_process,后面的都是傳遞的參數。
- 注意參數 --start-system-server,說明要啟動 SystemServer
- socket zygote stream 660 root system 表示創建名為 zygote 的 socket。
- 后面的 onrestart 關鍵字表示 zygote 進程重啟時所需執行的命令。 </ol>
- 創建一個 AppRuntime 實例 runtime
- 解析傳入的命令行參數
- 判斷調用哪一個 runtime.start,傳入對應的參數 </ol>
- Start the Android runtime. This involves starting the virtual machine
- and calling the "static void main(String[] args)" method in the class
- named by "className".
- 啟動 Android 運行時。這包括啟動虛擬機和調用 "className" 對應的類
- 的 "static void main(String[] args)" 方法。 *
- Passes the main function two arguments, the class name and the specified
- options string.
- 將會向指定類的 main 函數傳入兩個參數,也就是 start 函數的 className
和 options / void AndroidRuntime::start(const char className, const Vector<String8>& options, bool zygote) { ... / start the virtual machine / JniInvocation jni_invocation; jni_invocation.Init(NULL); JNIEnv* env; if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
} onVmCreated(env);
/*
Register android functions. */ if (startReg(env) < 0) { ALOGE("Unable to register all android natives\n"); return; }
...
/*
- Start VM. This thread becomes the main thread of the VM, and will
- not return until the VM exits.
/
char slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/ keep going /
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
if (startMeth == NULL) {"([Ljava/lang/String;)V");
} else {ALOGE("JavaVM unable to find main() in '%s'\n", className); /* keep going */
env->CallStaticVoidMethod(startClass, startMeth, strArray);
Register android functions. */ if (startReg(env) < 0) { ALOGE("Unable to register all android natives\n"); return; }</pre>
最后構建參數、創建 JNI 類對象,獲取 main 方法,并最終執行下面一行執行 main 入口:
env->CallStaticVoidMethod(startClass, startMeth, strArray);
這樣我們就成功從 C 中啟動了一個虛擬機,并加載了 Java 類 ZygoteInit,并進入到它的 main 方法中執行。
ZygoteInit
之后就來到了 ZygoteInit.java 的 main 方法,代碼位于 frameworks/base/core/java/com/android/internal/os/ZygoteInit.java。來看其 main 方法:
public static void main(String argv[]) { try {
... registerZygoteSocket(socketName); ... if (startSystemServer) { startSystemServer(abiList, socketName); } ... runSelectLoop(abiList); ...
} catch (...) { ... } }</pre>
首先,調用 registerZygoteSocket 創建了一個名為 zygote 的 socket:
registerZygoteSocket(socketName);
之后啟動 SystemServer 組件:
if (startSystemServer) { startSystemServer(abiList, socketName); }
最后調用 runSelectLoopMode 進入一個死循環,等待接受 socket 上由 ActivityManagerService 發來的請求創建應用程序的請求:
runSelectLoop(abiList);
下面我們就對后兩個步驟詳細分析。
一、啟動 SystemServer 組件
SystemServer 名為系統服務進程,負責啟動 Android 系統的關鍵服務。來看看函數的主要實現:
private static boolean startSystemServer(String abiList, String socketName)
throws MethodAndArgsCaller, RuntimeException {
... / Request to fork the system server process / pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, null, parsedArgs.permittedCapabilities, parsedArgs.effectiveCapabilities);
... / For child process / if (pid == 0) {
... handleSystemServerProcess(parsedArgs);
} return true; }</pre>
首先調用了 Zygote 的靜態方法 forkSystemServer 來創建 SystemServer 進程。這也是我首次看到 Zygote 是如何孵♂化出東西來的。
我們進入 forkSystemServer 看看具體實現:
public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
... int pid = nativeForkSystemServer(
uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
... return pid; }</pre>
可見,這又調用了 nativeForkSystemServer,這是一個 jni 調用,對應的函數為 com_android_internal_os_Zygote_nativeForkSystemServer,位于:frameworks/base/core/jni/com_android_internal_os_Zygote.cpp,來看看它的實現:
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids, jint debug_flags, jobjectArray rlimits, jlong permittedCapabilities, jlong effectiveCapabilities) {
pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
debug_flags, rlimits, permittedCapabilities, effectiveCapabilities, MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL, NULL, NULL);
... return pid; }</pre>
在這里調用了 ForkAndSpecializeCommon 函數,它是一個靜態函數,用來 fork Zygote 并設置子進程。代碼比較多,看看它的主要實現:
static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
jint debug_flags, jobjectArray javaRlimits, jlong permittedCapabilities, jlong effectiveCapabilities, jint mount_external, jstring java_se_info, jstring java_se_name, bool is_system_server, jintArray fdsToClose, jstring instructionSet, jstring dataDir) {
... pid_t pid = fork(); if (pid == 0) { ... // 對子線程進行了一大堆設置 ... } return pid; }</pre>
首先,執行 fork() 創建了一個子進程。在子進程中進行了一大堆設置。
跳了這么一大堆,來梳理一下。啟動 SystemServer,首先要創建一個新進程,可我們現在在 Java 中,需要會到 C 中進行 fork(),我們通過 forkSystemServer - com_android_internal_os_Zygote_nativeForkSystemServer - ForkAndSpecializeCommon 來實現 JNI 調用并成功 fork,這樣新進程就有了。
讓我們回到本節的一開始的 startSystemServer,現在子進程已經創建好了,接著往下看。在創建的子進程中,有一句 handleSystemServerProcess(parsedArgs),進入看看實現:
/**
Finish remaining work for the newly forked system server process. */ private static void handleSystemServerProcess(
ZygoteConnection.Arguments parsedArgs) throws ZygoteInit.MethodAndArgsCaller {
... final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH"); ... if (...) { ... } else { ClassLoader cl = null; if (systemServerClasspath != null) { cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader()); Thread.currentThread().setContextClassLoader(cl); }
/*
- Pass the remaining arguments to SystemServer.
/
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}</pre>
從中可以看出,我們從環境變量 SYSTEMSERVERCLASSPATH 拿到 SystemServer 的類名,之后載入進來,最后使用 RuntimeInit.zygoteInit 來運行,它來執行 SystemServer 的 main 方法。
RuntimeInit.zygoteInit 的具體實現可以簡單看一下:
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { ... commonInit(); // 基本設置(異常捕獲、時區、HTTP User-Agent 等) nativeZygoteInit(); applicationInit(targetSdkVersion, argv, classLoader); // 調用 Main 方法 }
其中 nativeZygoteInit() 是一個 jni 調用,位于 AndroidRuntime.cpp:
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv
env, jobject clazz) { gCurRuntime->onZygoteInit(); }</pre>onZygoteInit() 是 AppRuntime 中的方法,具體為:
virtual void onZygoteInit() { sp<ProcessState> proc = ProcessState::self(); ALOGV("App process: starting thread pool.\n"); proc->startThreadPool(); }
可見是啟動了一個線程池。nativeZygoteInit() 就分析到這里,由此可見,Zygote 啟動 SystemServer 的過程就算完了,之后的,都是 SystemServer 內部的事情了。
二、runSelectLoop
下面看看 runSelectLoop 的實現。
/**
- Pass the remaining arguments to SystemServer.
/
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}</pre>
- Runs the zygote process's select loop. Accepts new connections as
- they happen, and reads commands from connections one spawn-request's
- worth at a time.
- 運行 zygote 進程的 select 循環。接受新的連接,讀取指令。 *
- @throws MethodAndArgsCaller in a child process when a main() should
- be executed.
如果有 main() 需要被執行,拋出 MethodAndArgsCaller 異常。 */ private static void runSelectLoop(String abiList) throws MethodAndArgsCaller { ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>(); ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
fds.add(sServerSocket.getFileDescriptor()); peers.add(null);
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()]; for (int i = 0; i < pollFds.length; ++i) { pollFds[i] = new StructPollfd(); pollFds[i].fd = fds.get(i); pollFds[i].events = (short) POLLIN; } try { Os.poll(pollFds, -1); } catch (...) { ... } for (int i = pollFds.length - 1; i >= 0; --i) { if ((pollFds[i].revents & POLLIN) == 0) { continue; } if (i == 0) { ZygoteConnection newPeer = acceptCommandPeer(abiList); peers.add(newPeer); fds.add(newPeer.getFileDesciptor()); } else { boolean done = peers.get(i).runOnce(); if (done) { peers.remove(i); fds.remove(i); } } }
} }</pre>
首先獲取 socket 并加入到 fds 中:
fds.add(sServerSocket.getFileDescriptor());
之后執行:
Os.poll(pollFds, -1);
poll 會判斷 pollFds 是否可讀,若不可讀則阻塞等待。
之后進入 for 循環:
for (int i = pollFds.length - 1; i >= 0; --i) { if ((pollFds[i].revents & POLLIN) == 0) {
continue;
} if (i == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList); peers.add(newPeer); fds.add(newPeer.getFileDesciptor());
} else {
boolean done = peers.get(i).runOnce(); if (done) { peers.remove(i); fds.remove(i); }
} }</pre>
首先看是否已經在處理隊列中,若已在,則處理下一個。之后看新加的(最后一個又是未處理,那就是新家的),那就解析參數加進去。最后,對于已經加入的,判斷一下是否完成,完成了就從列表中刪除。
注意,這些代碼都套在 while(true) 死循環里,這個 poll 的過程會一直進行。
由此可見,Zygote 到這里就算啟動完了,并進入了一個死循環,要想啟動個東西,就從 socket 向它發指令,他就會孵♂化。
至此,我關于 Zygote 的疑問基本搞明白了。本文對于 Zygote 的機制挖掘并不很深,對于 Zygote 的底層操作也沒有挖掘徹底。我想,對于了解來說,已經足夠了。
來自:http://www.judymax.com/archives/1118
現有資源
現有的關于 Zygote 的文章已有很多。但是紙上得來終覺淺,絕知此事要孤行。前輩分享的知識,吃透理解后,沉淀成自己的東西才算是自己的。
在這篇文章中,我主要學習了鄧凡平的《Android深入淺出之Zygote》、老羅的《Android系統進程Zygote啟動過程的源代碼分析》。感謝這些前輩的無私奉獻,它們的努力,使我在后來的學習中減少了許多困難。
誰負責啟動 Zygote?
既然 Zygote 負責啟動 Android 系統的各個部分,我的第一個問題是它自己是如何自舉的?
Android 以 Linux 為核心,這個問題交給了 Linux。init 程序 Linux 中負責載入 Linux 各個部分的程序,它在成功加載 Linux 系統后,按照 Android 啟動腳本 init.rc 文件中的配置,加載 Zygote。
配置文件在 Android 6.0 代碼中位于 system/core/rootdir/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
其中:
Zygote 的啟動
從中我們可以得出結論: zygote 只是服務的名稱,與此服務對應的程序是 app_process 程序,我們研究 zygote 的實現,就是要研究 app_process 程序。
app_process 程序
app_process 代碼位于 frameworks/base/cmds/app_process/app_main.cpp,入口函數為 main。將 main 函數的主要邏輯抽象出來:
int main(int argc, char* const argv[]) { ... AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); ... // 解析參數,設置 Flag... ... if (zygote) { runtime.start("com.android.internal.os.ZygoteInit", args, zygote); } else if (className) { runtime.start("com.android.internal.os.RuntimeInit", args, zygote); } else { ... return 10; } }
main 的大體流程為:
由于 init.zygote32.rc 中傳入參數 -Xzygote /system/bin --zygote --start-system-server,因此將執行:
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
由此可知,app_process 沒干什么主要的事情,只是跳轉到 Java 類 com.android.internal.os.ZygoteInit,看來工作都在 ZygoteInit 中完成。
在跳到 ZygoteInit 之前,先來看看 app_process 中用到的 AppRuntime。
AndroidRuntime
start 方法來自于 AppRuntime 的父類 AndroidRuntime,代碼位于 frameworks/base/core/jni/AndroidRuntime.cpp。來看 start 方法 (在 6.0 代碼中位于 1007 行):
/*
if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
endif
}
}
free(slashClassName);
...
}</pre>
AndroidRuntime 的 runtime 主要做了三件事:
首先是創建虛擬機:
/* start the virtual machine */ JniInvocation jni_invocation; jni_invocation.Init(NULL); JNIEnv* env; if (startVm(&mJavaVM, &env, zygote) != 0) { return; } onVmCreated(env);
之后是調用 startReg 函數注冊 JNI 方法:
/*