--- title: 'Android 啟動過程 - Zygote 進程' disqus: kyleAlien --- Zygote 進程 === [**init 進程**](https://hackmd.io/pJpAeKAeRea0VIW3oI-mXw?view) 會透過分析 .rc 檔案來 `fork` + `execv` Zygote 進程 ## OverView of Content [TOC] ## 系統進程之間 - 關係 這個章節著重講解的是 **++Zygote 進程++**,但了解它的來源也是相當重要的,請參考下圖 > ![](https://i.imgur.com/ZNKX6wT.png) ### Zygote 進程 - 概述 * Zygote 進程又稱回 **孵化器**,之後啟動的 APP 進程 or SystemServer 都是以 **Zygote 作為模板來 fork,但 ++不執行 execv++**,因為它會在前面創建幾個重要的零件 1. **DVM、ART 虛擬機** 2. **加載系統基礎資源 android framework** * **Zygote 只是該服務的名稱,但並不是要執行的檔案**,**`app_process` 才是 init 進程要執行的檔案** :::info * Zygote 是一個 **C/S 模型** (使用 Socket) **Zygote 進程作為服務端 (主要負責創建 Java Vm、加載系統資源、啟動 SystemServer 進程)** 其他客戶端應用程式若要啟動 (eg. AMS 就是客戶端),就會對 Zygote 發出請求,而 Zygote 就會 fork 出一個新進程 (forkAndSpecialize) ::: > ![](https://i.imgur.com/31cwX2M.png) * 從 `init.rc` 被 init 進程分析後,觸發 `app_main.cpp` 的流程圖 > ![](https://i.imgur.com/HZstNk8.png) ### 透過 init.rc 啟動 Zygote * 關於 init 進程如何分析 `init.rc` 並執行可以參考 [**Android 啟動過程 - init 進程**](https://hackmd.io/zhLTuxZ-RjewJEhDuC73uQ#Zygote-%E6%9C%8D%E5%8B%99),以下以 `init.zygote64_32.rc` 為例 ```shell= # /rootdir/init.zygote64_32.rc # 1. Service Name = zygote # 2. Path = system/bin/app_process64,app_process64 是資料夾 # 3. Argument: # -Xzygote /system/bin --zygote --start-system-server # 主 zygote service zygote /system/bin/app_process64 \ -Xzygote /system/bin --zygote --start-system-server # 4. 分類為 main 群組 class main priority -20 user root group root readproc reserved_disk ## 啟動兩個 Socket,權限為 660 socket zygote stream 660 root system socket usap_pool_primary stream 660 root system onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse ... # zygote_secondary 為輔助 service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload class main priority -20 user root group root readproc reserved_disk socket zygote_secondary stream 660 root system socket usap_pool_secondary stream 660 root system onrestart restart zygote task_profiles ProcessCapacityHigh MaxPerformance ``` * 從上面可以看到啟動的路徑是 `app_process64`,這在 `frameworks/base/cmds/app_process` 中,所以先來看 [**/cmds/app_process**](https://android.googlesource.com/platform/frameworks/base/+/master/cmds/app_process) 資料夾內的 [**Android.bp 檔**](https://android.googlesource.com/platform/frameworks/base/+/master/cmds/app_process/Android.bp) > ![](https://i.imgur.com/MBu9xFQ.png) ### Zygote 進程啟動 Socket * 透過 init 進程分析 `init.rc` 檔後,會將 Zygote 要啟動的 Socket 參數也一併紀錄,並在啟動 Zygote (或指定服務) 時,順代啟動 Socket :::success * 分析過程可以參考 [**ParseLineSection 處理 section 參數 - 添加 Socket**](https://hackmd.io/zhLTuxZ-RjewJEhDuC73uQ#ParseLineSection-%E8%99%95%E7%90%86-section-%E5%8F%83%E6%95%B8---%E6%B7%BB%E5%8A%A0-Socket) ::: * C++ 啟動 [**service**](https://cs.android.com/android/platform/superproject/+/master:system/core/init/service.cpp) 的過程如下:創建必要 Socket,再來主要是透過 `fork` + `exec` 這兩個 SystemCall 在 init 進程開啟一個新進程 ```cpp= // /init/service.cpp Result<void> Service::StartIfNotDisabled() { // 判斷是否 Disable if (!(flags_ & SVC_DISABLED)) { return Start(); } else { flags_ |= SVC_DISABLED_START; } return {}; } Result<void> Service::Start() { ... 省略部分判斷 pid_t pid = -1; if (namespaces_.flags) { pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr); } else { // 使用 fork 創建子進程 pid = fork(); } std::vector<Descriptor> descriptors; for (const auto& socket : sockets_) { // 透過 Create 函數創建 Socket 物件 // @ 分析 Create if (auto result = socket.Create(scon); result.ok()) { descriptors.emplace_back(std::move(*result)); } else { ... log msg } } ... 省略部分 if (pid == 0) { umask(077); ... 省略部分 // 執行 ececv 函數,並啟動 Service 子進程 if (!ExpandArgsAndExecv(args_, sigstop_)) { PLOG(ERROR) << "cannot execv('" << args_[0] << "'). See the 'Debugging init' section of init's README.md for tips"; } _exit(127); } } ``` * 查看 [**service_utils**](https://cs.android.com/android/platform/superproject/+/master:system/core/init/service_utils.cpp)#Create 函數:呼叫 `CreateSocket` 函數 (下面再說)、`Descriptor` 函數則會創建一個 `ANDROID_SOCKET_`+`<name>` 的檔案描述 > 目前是創建 `ANDROID_SOCKET_zygote` 檔案描述 ```cpp= // socket.h #define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_" // ---------------------------------------------------------------- // service_utils.cpp Result<Descriptor> SocketDescriptor::Create(const std::string& global_context) const { const auto& socket_context = context.empty() ? global_context : context; // 查看 CreateSocket auto result = CreateSocket(name, type | SOCK_CLOEXEC, passcred, listen, perm, uid, gid, socket_context); if (!result.ok()) { return result.error(); } return Descriptor(ANDROID_SOCKET_ENV_PREFIX + name, unique_fd(*result)); } ``` * [**util**](https://cs.android.com/android/platform/superproject/+/master:system/core/init/util.cpp)#**`CreateSocket` 函數**:這個函數才是真正創建 Socket 的地方,這裡需要做的事情如下 1. 創建 `socket` 2. 創建一個 `sockaddr_un`,其類型為 `AF_UNIX`,之後會創建一個 `"/dev/socket/<name>"` 的虛擬裝置 > 目前是創建 `/dev/socket/socket` 虛擬裝置檔案 :::info * **AF_UNIX** AF_UNIX 型態的 Socket 是用來執行畚箕處理程序間的通訊標誌 ::: 3. 使用 `chown`、`chmod` 設定該 Socket 檔案權限 > 目前 Zygote 設定為 660 ```cpp= // socket.h #define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_" #define ANDROID_SOCKET_DIR "/dev/socket" // ---------------------------------------------------------------- // util.cpp Result<int> CreateSocket(const std::string& name, // 在 init.rc 設定的名稱 int type, // 當前是 stream bool passcred, bool should_listen, mode_t perm, uid_t uid, gid_t gid, const std::string& socketcon) { ... 省略部分 // 1. 創建 `socket` android::base::unique_fd fd(socket(PF_UNIX, type, 0)); if (fd < 0) { return ErrnoError() << "Failed to open socket '" << name << "'"; } ... // 2. 創建一個 `sockaddr_un` struct sockaddr_un addr; memset(&addr, 0 , sizeof(addr)); addr.sun_family = AF_UNIX; // 處理本機通訊 snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR "/%s", name.c_str()); ... int ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr)); ... // 修改檔案權限 if (lchown(addr.sun_path, uid, gid)) { return ErrnoError() << "Failed to lchown socket '" << addr.sun_path << "'"; } if (fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW)) { return ErrnoError() << "Failed to fchmodat socket '" << addr.sun_path << "'"; } ... return fd.release(); } ``` ### Zygote - app_process - [Android.bp](https://android.googlesource.com/platform/frameworks/base/+/master/cmds/app_process/Android.bp) 檔 (觸發 app_main.cpp) :::info 有關 **==Bp 檔簡單來說就是替換 Android.mk 的組態檔==**,詳細使用 & 介紹可以看這一篇 [**文章**](https://www.gushiciku.cn/pl/pSrC/zh-tw) ::: * **Android.bp** 檔案中的模組,以 ++模組型別++ 開頭,後面跟一組 name: "value",格式的屬性 (Like Json Format) ```json= // Example cc_binary { // 每個模塊都要有 name 屬性 name: "gzip", // 指定建構模組的原始檔 srcs: ["src/test/minigzip.c"], shared_libs: ["libz"], stl: "none", } ``` * 以下就是 Android.bp 建構 Multilib (32、64 位元) 的一個腳本,詳細請看註釋 ```json= // /cmds/app_process/Android.bp ... cc_binary { name: "app_process", // 觸發的檔案名稱 srcs: ["app_main.cpp"], // 建構的版本,目前分為 32/64 位元 multilib: { lib32: { suffix: "32", // 串接在後面 }, lib64: { suffix: "64", // 串接在後面 }, }, version_script: "version-script.txt", // 依賴的厙 shared_libs: [ "libandroid_runtime", "libbinder", "libcutils", "libdl", "libhidlbase", "liblog", "libnativeloader", "libsigchain", "libutils", "libwilhelm", ], // 準備建構的版本,both 代表 32/64 都建構 compile_multilib: "both", // C 語言的設定 cflags: [ "-Wall", "-Werror", "-Wunused", "-Wunreachable-code", ], sanitize: { memtag_heap: true, }, } ``` > ![](https://i.imgur.com/DT0GOm4.png) ## Zygote 啟動過程 `app_main.cpp#main` 中,主要做的就是參數解析 (**解析 `rc 檔` 傳入的參數**),並 **分成 ++2 種++ 啟動模式** 1. Zygote 模式: 初始化 Zygote 進程 2. Application 模式: 啟動普通的 APP 進程 (傳遞的參數有 class name、class 參數) 而上述兩者最終都會執行 **`AndroidRuntime#start` 方法** > ![](https://i.imgur.com/HQwNibe.png) ### Zygote 服務 - 分析 rc 傳入的參數 * **`app_process` 是透過 `Android.bp 檔` 所喚醒**,接下來分析 `app_main.cpp` 檔案的 main 函數 ([**app_main.cpp**](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/cmds/app_process/app_main.cpp) 中),**main 函數會先分析 rc 檔案所傳入的 argument** ```shell= # /rootdir/init.zygote64.rc # 1. Service Name = `zygote` # 2. Path = `system/bin/app_process64` # 3. Argument: `-Xzygote /system/bin --zygote --start-system-server` # # (這些參數會傳入 app_main 進行分析) service zygote /system/bin/app_process64 \ -Xzygote /system/bin --zygote --start-system-server ... 省略部分 ``` | argument | 功能 | | -------- | -------- | | -\-zygote | 當前進程用於承載 zygote | | -\-start-system-server | 是否需要啟動 system server | | -\-application | 啟動進入獨立的程序模式 (一般 APP 啟動) | | -\-nice-name= | 對於進程的別名 | ```cpp= // /cmds/app_process/app_main.cpp int main(int argc, char* const argv[]) { ... bool zygote = false; bool startSystemServer = false; bool application = false; String8 niceName; String8 className; ++i; // Skip unused "parent dir" argument. // 分析 rc 傳入的 argument while (i < argc) { const char* arg = argv[i++]; // strcmp 比較字串無差異就返回 0 if (strcmp(arg, "--zygote") == 0) { // 當前進程是否用於承載 zygote zygote = true; niceName = ZYGOTE_NICE_NAME; } else if (strcmp(arg, "--start-system-server") == 0) { // 是否用於啟動 system service startSystemServer = true; } else if (strcmp(arg, "--application") == 0) { application = true; } else if (strncmp(arg, "--nice-name=", 12) == 0) { // 限制長度為 12 niceName.setTo(arg + 12); } else if (strncmp(arg, "--", 2) != 0) { className.setTo(arg); break; } else { --i; break; } } ... 先暫時省略下半部 } ``` ### AndroidRuntime - 啟動 Java ZygoteInit 類 :::success * AppRuntime#start 這個方法就會調用到 Java 層代碼,並透過 AndroidRuntime 做到以下工作的初始化 (當然不只這些) 1. 啟動 JVM 2. 註冊 JNI 3. Java Heap 4. ClassLoader ::: * **由於 ZygoteInit 是 java 語言**,所以 AndroidRuntime.cpp 要透過 JNI 來調用到 Java 層,啟動 Android Runtime 詳細啟動請看 [**Runtime 篇**](https://hackmd.io/SKv3cRkNTl66owHVhVG8Ow?view) ```cpp= // /cmds/app_process/app_main.cpp int main(int argc, char* const argv[]) { ... // argv[0] 是啟動名稱,eg. zygote AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); int i; ...依照分析的參數啟動 Android Runtime // init.zygote64.rc 傳入參數分析過後,zygote = true if (zygote) { // 啟動 Zygote 服務 // runtime 是 AndroidRuntime 對象 // 啟動 ZygoteInit 類 runtime.start("com.android.internal.os.ZygoteInit", args, zygote); } else if (className) { // 啟動指定 Class runtime.start("com.android.internal.os.RuntimeInit", args, zygote); } else { ... } } ``` * 目前的情況是 `app_main.cpp` **對 AppRuntime 傳入 zygote + class 路徑** 後,執行 **AppRuntime#`start` 函數** > runtime.start("com.android.internal.os.ZygoteInit", args, zygote) ```cpp= // app_main.cpp // AppRuntime 繼承於 AndroidRuntime class AppRuntime : public AndroidRuntime { ... 省略 } ``` 1. **startVm 函數**:**ZygoteInit 就會啟動在 Java 虛擬機上**(透過 [**AndroidRuntime**](https://android.googlesource.com/platform/frameworks/base/+/master/core/jni/AndroidRuntime.cpp) 的 start 函數) 2. **startReg 函數**:**啟動 Java 虛擬機註冊 JNI 方法**,其中就包括 Binder 會使用到的 JNI ```cpp= // /core/jni/AndroidRuntime.cpp void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { ... JNIEnv* env; // 1. 啟動 Java 虛擬機 if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) { return; } // 啟動後的回調 onVmCreated(env); /* * 2. Register android functions. */ if (startReg(env) < 0) { ALOGE("Unable to register all android natives\n"); return; } ... 省略部分 } ``` 3. **從 Native 進入 Java 層**:**VM 啟動後就會透過 JNI,進入指定 Java 類 (根據傳入 class name 為主,eg. ZygoteInit.java) 的 ==main 函數==** (Java 的啟動入口) ```cpp= // /core/jni/AndroidRuntime.cpp // 當前狀況 class Name 傳入:"com.android.internal.os.ZygoteInit" void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { ... 省略部分 (上面就是啟動 JVM) jclass stringClass; jobjectArray strArray; jstring classNameStr; // 參數 stringClass = env->FindClass("java/lang/String"); assert(stringClass != NULL); strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL); assert(strArray != NULL); // 目標 Java class classNameStr = env->NewStringUTF(className); assert(classNameStr != NULL); // 將目標 class name 設定成 Array 的第一個元素 env->SetObjectArrayElement(strArray, 0, classNameStr); // 設定傳入 main 的參數 for (size_t i = 0; i < options.size(); ++i) { jstring optionsStr = env->NewStringUTF(options.itemAt(i).string()); assert(optionsStr != NULL); env->SetObjectArrayElement(strArray, i + 1, optionsStr); } /* * 啟動虛擬機 * * 該線程成為虛擬機的主線程,並將在虛擬機退出之前不返回。 */ // 替換傳入的 className "." -> "/" // 轉換後 com/android/internal/os/ZygoteInit char* slashClassName = toSlashClassName(className != NULL ? className : ""); // 找目標 class jclass startClass = env->FindClass(slashClassName); if (startClass == NULL) { // JVM 無法啟動的 Log ALOGE("JavaVM unable to locate class '%s'\n", slashClassName); /* keep going */ } else { // 找 class 中的靜態 main 函數 jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); if (startMeth == NULL) { ... log msg } else { env->CallStaticVoidMethod(startClass, startMeth, strArray); #if 0 if (env->ExceptionCheck()) threadExitUncaughtException(env); #endif } } // 釋放指針空間 free(slashClassName); ALOGD("Shutting down VM\n"); // 該進程若是結束就會關閉該 JVM if (mJavaVM->DetachCurrentThread() != JNI_OK) ALOGW("Warning: unable to detach main thread\n"); if (mJavaVM->DestroyJavaVM() != 0) ALOGW("Warning: VM did not shut down cleanly\n"); } ``` > ![](https://i.imgur.com/NvEs7vr.png) ### [ZygoteInit](https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/com/android/internal/os/ZygoteInit.java) - 建構 ZygoteServer 對象 * Zygote JVM 啟動後就會執行 ZygoteInit.java 的 main 函數,首先先回顧 `init.zygote64.rc` 傳入的參數(`--start-system-server`),這些參數會傳到 main#argv ```shell= # /rootdir/init.zygote64.rc # 1. Service Name = zygote # 2. Path = system/bin/app_process64 # 3. Argument: -Xzygote /system/bin --zygote --start-system-server service zygote /system/bin/app_process64 \ -Xzygote /system/bin --zygote --start-system-server ... ``` * **在 VM 啟動 ZygoteInit 類後就會先進入 main 函數後**,^1^ 判斷 init.zygote64.rc 傳入參數,^2^ 建構一個 ZygoteServer 對象,^3^ 透過 `forkSystemServer()` 方法啟動 SystemServer 服務進程 ```java= // /android/internal/os/ZygoteInit.java public static void main(String[] argv) { ... try { ... boolean startSystemServer = false; String zygoteSocketName = "zygote"; String abiList = null; boolean enableLazyPreload = false; // 1. 判斷傳入的參數 for (int i = 1; i < argv.length; i++) { // 當前就是傳入 "start-system-server" if ("start-system-server".equals(argv[i])) { // 需要啟動 SystemServer startSystemServer = true; } else if ("--enable-lazy-preload".equals(argv[i])) { // 是否懶加載資源 // 像是 zygote_secondary 為輔助 就有傳入該參數 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)) { zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length()); } else { throw new RuntimeException("Unknown command line argument: " + argv[i]); } } ... // 判斷裝置是否有可使用的 ABI if (abiList == null) { throw new RuntimeException("No ABI list supplied."); } if (!enableLazyPreload) { ... preload(bootTimingsTraceLog); // 預加載資源 (下面解釋) ... } ... // 2. 建構一個 ZygoteServer 對象 // (將 Zygote 進程作為 Socket 的 Server 端) !! zygoteServer = new ZygoteServer(isPrimaryZygote); if (startSystemServer) { // 3. fork System Server 返回一個 Runnable // @ 接下來會 ++分析 forkSystemServer 方法++ Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); // {@code r == null} in the parent (zygote) process, // and {@code r != null} in the child (system_server) process. if (r != null) { r.run(); // 直接執行 // fork SystemServer 成功後直接跳出 // (跳出後會先跑到 finally return; } } ... // Zygote 進入循環 Loop,等待 AMS 的請求 !! caller = zygoteServer.runSelectLoop(abiList); } catch (Throwable ex) { Log.e(TAG, "System zygote died with exception", ex); throw ex; } finally { if (zygoteServer != null) { // 關閉 socket zygoteServer.closeServerSocket(); } } // caller 是一個 Runnable 類型 if (caller != null) { caller.run(); // 其內容包裝的是 fork 出來的靜態 main 方法 } } ``` :::info 從這裡可以看到 SystemServer 是沒有 Socket 的,它在 Fork Zygote 成功後,就會關閉 Socket ::: * **preload 函數**:預加載的資源,用於加載虛擬機運行時所需的各種資源 ```java= // ZygoteInit.java static void preload(TimingsTraceLog bootTimingsTraceLog) { ... preloadClasses(); // framework.jar preloadResources(); // 加載 Drawable、color、style、array... 等系統預設資源 preloadSharedLibraries(); // 共用 C、C++ Lib preloadTextResources(); // 加載 Text 資源、字體 ... } ``` :::info * **preloadClasses 使用** 像是需要加載的 classes 就會被紀錄在 `framework.jar` 的 preloaded-classed 中 preload 函數其實也是很耗費 手機啟動時間的,但在加載完後,其他 fork 的進程 (一般應用 APP) 都會使用加載好的資源 > 使用虛擬記憶體的 [**Copy-on-write**](https://hackmd.io/ptxTEwCzQBuxv61dGL_lvA#%E5%AF%AB%E5%85%A5%E6%99%82%E8%A4%87%E8%A3%BD-Copy-on-write---%E9%AB%98%E6%95%88%E8%A1%8C%E7%A8%8B%E5%BB%BA%E7%AB%8B) 技術 ::: > ![](https://i.imgur.com/tcCElgP.png) ### [ZygoteInit](https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/com/android/internal/os/ZygoteInit.java) - 啟動 SystemServer * 在 ZygoteInit#main 函數中,若是有攜帶 `start-system-server` 參數,那就會執行 **[forkSystemServer 函數](https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/com/android/internal/os/ZygoteInit.java#663)**,forkSystemServer 函數則會 fork 出一個子進程 :::success * `Zygote.forkSystemServer` 函數: 最終會使用 UNIX 的 fork 機制,**核心複製當前的 ++分頁表++,創建了一個新記憶體空間** (新進程) ::: * 可以看到內部實現的主要順序是 1. **分析 hardcode 的指令參數** 2. **ZygoteArguments 分析 cmd** 3. **[Zygote](https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/com/android/internal/os/Zygote.java)#forkSystemServer 一個新進程**(fork 成功後就可以得到 pid 值) 4. 若 fork 成功 (`forkSystemServer` 方法返回 0 代表成功),**啟動 System Server** ```java= // /internal/os/ZygoteInit.java private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) { ... // 1. hardcode 指令參數,之後會分析使用這些指令 String[] args = { // 用戶 id "--setuid=1000", // 群組 id "--setgid=1000", // 擁有的群組 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023," + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011", "--capabilities=" + capabilities + "," + capabilities, "--nice-name=system_server", "--runtime-args", "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT, // 進程名稱 "com.android.server.SystemServer", }; ZygoteArguments parsedArgs; int pid; try { ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args); try { // 2. ZygoteArguments 分析 cmd parsedArgs = ZygoteArguments.getInstance(commandBuffer); } catch (EOFException e) { throw new AssertionError("Unexpected argument error for forking system server", e); } commandBuffer.close(); ... 省略部分 // 3. fork 一個新進程 pid = Zygote.forkSystemServer( parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids, parsedArgs.mRuntimeFlags, null, parsedArgs.mPermittedCapabilities, parsedArgs.mEffectiveCapabilities); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } /* For child process */ // pid == 0 代表成功 fork 出子進程 if (pid == 0) { // 目前子進程是 SystemServer 進程 // 如果有備用 Zygote 則進行等待 if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } // 由於 已經 fork 出一個新的進程,所以這個是關閉 SystemServer 的 Socket zygoteServer.closeServerSocket(); // 4. 啟動 System Server 進程 return handleSystemServerProcess(parsedArgs); } // Parent Process (Zygote) 就是走這裡,返回 null return null; } ``` :::success * **`fork` 函數返回值**:使用 `fork` 返回時代表了兩種情況 1. Parent Proc:`fork` 返回得到 ChildProc 的 pid 參數 2. Child Proc:`fork` 返回 0 代表成功,其他則是失敗 ::: > ![](https://i.imgur.com/9BMjRKu.png) ### ZygoteInit 進程 - 創建 Socket 監聽 :::info 目前是仍在 Zygote 進程分析 ::: * 啟動 SystemServer 進程後 **Zygote 進程** 就會使用呼叫 **[ZygoteServer](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/com/android/internal/os/ZygoteServer.java)#runSelectLoop** 方法 (**==SystemServer 進程不會走到 runSelectLoop 方法==**) 1. 手動添加 mZygoteSocket 的 FD 成為該 Array 列表的第一個 (之後會使用到) ```java= // ZygoteServer.java /** * Listening socket that accepts new server connections. */ private LocalServerSocket mZygoteSocket; Runnable runSelectLoop(String abiList) { ArrayList<FileDescriptor> socketFDs = new ArrayList<>(); ArrayList<ZygoteConnection> peers = new ArrayList<>(); // 1. 加入自身 FD (第一個 FD,再輪詢時會使用到) socketFDs.add(mZygoteSocket.getFileDescriptor()); // 配合 mZygoteSocket 添加一個 null peers.add(null); mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP; .... } ``` :::info * **FD (mZygoteSocket)是透過 name**,到全域系統中找到對應的 Socket (透過系統環境變數中取得 `System.getenv()` > **目前的 name 就是 `ANDROID_SOCKET_zygote`,也 ==就是取得 Native Zygote 創建的 Socket==** > > ![](https://i.imgur.com/mlXgZ6M.png) ::: 2. 透過 while 無限循環,來達成 ZygoteInit 的 ServerSocket 不斷循環監聽 Socket 請求 3. 分配空間給 StructPollfd array ```java= // ZygoteServer.java /** * Listening socket that accepts new server connections. */ private LocalServerSocket mZygoteSocket; Runnable runSelectLoop(String abiList) { // 紀錄 ServerClient ArrayList<FileDescriptor> socketFDs = new ArrayList<>(); ArrayList<ZygoteConnection> peers = new ArrayList<>(); // ServerSocket 加入列表 socketFDs.add(mZygoteSocket.getFileDescriptor()); peers.add(null); ... // 2. 讓呼叫者 (ZygoteInit) 進入無限循環 while (true) { fetchUsapPoolPolicyPropsWithMinInterval(); mUsapPoolRefillAction = UsapPoolRefillAction.NONE; int[] usapPipeFDs = null; StructPollfd[] pollFDs; // 為輪詢結構分配足夠的空間 (給 StructPollfd Array 空間) // (可以是常規 Zygote、WebView Zygote 或 AppZygote)。 if (mUsapPoolEnabled) { // 同時考慮此 Zygote 的 USAP 池的狀態 usapPipeFDs = Zygote.getUsapPipeFDs(); pollFDs = new StructPollfd[socketFDs.size() + 1 + usapPipeFDs.length]; } else { pollFDs = new StructPollfd[socketFDs.size()]; } // 當前輪巡的 index int pollIndex = 0; for (FileDescriptor socketFD : socketFDs) { // 3-1. 賦予 pollFDs Array 每個元素值 pollFDs[pollIndex] = new StructPollfd(); pollFDs[pollIndex].fd = socketFD; pollFDs[pollIndex].events = (short) POLLIN; ++pollIndex; } final int usapPoolEventFDIndex = pollIndex; if (mUsapPoolEnabled) { // 3-2. 賦予 pollFDs 值 pollFDs[pollIndex] = new StructPollfd(); pollFDs[pollIndex].fd = mUsapPoolEventFD; pollFDs[pollIndex].events = (short) POLLIN; ++pollIndex; // The usapPipeFDs array will always be filled in if the USAP Pool is enabled. assert usapPipeFDs != null; for (int usapPipeFD : usapPipeFDs) { FileDescriptor managedFd = new FileDescriptor(); managedFd.setInt$(usapPipeFD); pollFDs[pollIndex] = new StructPollfd(); pollFDs[pollIndex].fd = managedFd; pollFDs[pollIndex].events = (short) POLLIN; ++pollIndex; } } ... 檢查時間 int pollReturnValue; try { pollReturnValue = Os.poll(pollFDs, pollTimeoutMs); } catch (ErrnoException ex) { throw new RuntimeException("poll failed", ex); } // 當超時,就會返回 0 if (pollReturnValue == 0) { // 或是發出非阻塞輪巡,並且 沒有 FD 準備好 // 就應該重新填充 FD 池 mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP; mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED; } else { ... } } } ``` 4. **判斷若是第一個 FD,則創建新 ZygoteConnection,該 ++ZygoteConnection 用來接收 AMS 創建應用 APP 進程的請求++** ```java= // ZygoteServer.java /** * Listening socket that accepts new server connections. */ private LocalServerSocket mZygoteSocket; Runnable runSelectLoop(String abiList) { ArrayList<FileDescriptor> socketFDs = new ArrayList<>(); ArrayList<ZygoteConnection> peers = new ArrayList<>(); // 2. 讓呼叫者 (ZygoteInit) 進入無限循環 while (true) { // 當超時,就會返回 0 if (pollReturnValue == 0) { ... } else { boolean usapPoolFDRead = false; // 輪巡 不同的 FD (FileDescriptor) while (--pollIndex >= 0) { // 輪巡檢查 if ((pollFDs[pollIndex].revents & POLLIN) == 0) { // 如果不需要輪尋則繼續往下一個檢查 continue; } // 在上面有手動作第一個添加的 FD if (pollIndex == 0) { // Zygote 進程 Socket 已經與 AMS Socket 連線 // 4. 呼叫 acceptCommandPeer 創建新 // ZygoteConnection ZygoteConnection newPeer = acceptCommandPeer(abiList); peers.add(newPeer); socketFDs.add(newPeer.getFileDescriptor()); } else if(...) { ... } else { ... } } } ... } ... } // 創建新的 ZygoteConnection,接收單個命令連結 private ZygoteConnection acceptCommandPeer(String abiList) { try { // 創建與 Zygote ServerSocket 連接的 Socket return createNewConnection(mZygoteSocket.accept(), abiList); } catch (IOException ex) { throw new RuntimeException( "IOException during accept()", ex); } } ``` 5. 接收到 ClientSocket 後再透過 [**ZygoteConnection**](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/com/android/internal/os/ZygoteConnection.java)#**processCommand** 準備 fork 新進程 (一般的應用 APP),結果會依照不同進程做不同的行為 (如下) - Child fork 成功就會返回要執行的 Runnable(內部其實是包目標 class 的 main 方法),並跳出循環 - Parent 則會返回 null,繼續循環監聽 ```java= // ZygoteServer.java /** * Listening socket that accepts new server connections. */ private LocalServerSocket mZygoteSocket; Runnable runSelectLoop(String abiList) { ArrayList<FileDescriptor> socketFDs = new ArrayList<>(); ArrayList<ZygoteConnection> peers = new ArrayList<>(); // 2. 讓呼叫者 (ZygoteInit) 進入無限循環 while (true) { // 當超時,就會返回 0 if (pollReturnValue == 0) { ... } else { // 輪巡 不同的 FD (FileDescriptor) while (--pollIndex >= 0) { ... if (pollIndex == 0) { ... } else if (pollIndex < usapPoolEventFDIndex) { // Zygote 接收 Session ClientSocket try { ZygoteConnection connection = peers.get(pollIndex); boolean multipleForksOK = !isUsapPoolEnabled() && ZygoteHooks.isIndefiniteThreadSuspensionSafe(); // 5. 透過 ZygoteConnection#processCommand 進行真正 fork // a. Child fork 成功就會返回要執行的 Runnable // b. Parent 則會返回 null // 分析 @ processCommand 方法 final Runnable command = connection.processCommand(this, multipleForksOK); if (mIsForkChild) { // We're in the child. We should always have a command to run at // this stage if processCommand hasn't called "exec". if (command == null) { throw new IllegalStateException("command == null"); } // Child Process 將靜態 main 方法包裝並返回 return command; } else { ... } } /* 省略 catch、finally */ } else { ... 省略部分 } } ... 省略部分 } ... 省略部分 } } ``` * 透過 [**ZygoteConnection**](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/com/android/internal/os/ZygoteConnection.java)#processCommand 呼叫到 [**Zygote**](https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/com/android/internal/os/Zygote.java#334)#forkAndSpecialize 方法:該方法會以 Zygote 為樣本 fork 出一個新 APP 進程 ```java= // ZygoteConnection.java Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) { ZygoteArguments parsedArgs; try (ZygoteCommandBuffer argBuffer = new ZygoteCommandBuffer(mSocket)) { while (true) { try { ... 省略部分 FileDescriptor fd = mSocket.getFileDescriptor(); if (fd != null) { fdsToClose[0] = fd.getInt$(); } FileDescriptor zygoteFd = zygoteServer.getZygoteSocketFileDescriptor(); if (zygoteFd != null) { fdsToClose[1] = zygoteFd.getInt$(); } if (parsedArgs.mInvokeWith != null || parsedArgs.mStartChildZygote || !multipleOK || peer.getUid() != Process.SYSTEM_UID) { // @ 分析 forkAndSpecialize 方法 pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName, /* 省略部分參數 */); try { if (pid == 0) { // in child zygoteServer.setForkChild(); zygoteServer.closeServerSocket(); IoUtils.closeQuietly(serverPipeFd); serverPipeFd = null; // child process 呼叫 handleChildProc return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote); } else { // In the parent. A pid < 0 indicates a failure and will be handled in // handleParentProc. IoUtils.closeQuietly(childPipeFd); childPipeFd = null; handleParentProc(pid, serverPipeFd); return null; } } finally { IoUtils.closeQuietly(childPipeFd); IoUtils.closeQuietly(serverPipeFd); } } } /* 省略 catch */ } ... 省略部分 } } // ----------------------------------------------------------------------------------- // Zygote.java static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName /*省略部分入參*/ ) { ZygoteHooks.preFork(); // 最終使用 Linux System call "fork" int pid = nativeForkAndSpecialize( uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp, pkgDataInfoList, allowlistedDataInfoList, bindMountAppDataDirs, bindMountAppStorageDirs); // fork 成功 if (pid == 0) { // Note that this event ends at the end of handleChildProc, Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); // If no GIDs were specified, don't make any permissions changes based on groups. if (gids != null && gids.length > 0) { NetworkUtilsInternal.setAllowNetworkingForProcess(containsInetGid(gids)); } } ... 省略部分 return pid; } ``` ## Zygote Fork SystemServer 進程 * 在 ZygoteInit#main 函數中,若是有攜帶 `start-system-server` 參數,那就會執行 **[forkSystemServer 函數](https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/com/android/internal/os/ZygoteInit.java#663)**,forkSystemServer 函數則會 fork 出一個子進程 :::success * Zygote.forkSystemServer 函數: 最終會使用 UNIX 的 fork 機制,複製當前的分頁表,創建了一個新記憶體空間 (新進程) ::: * 可以看到內部實現的主要順序是 1. **分析 hardcode 的指令參數** 2. **ZygoteArguments 分析 cmd** 3. **[Zygote](https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/com/android/internal/os/Zygote.java)#forkSystemServer 一個新進程**(fork 成功後就可以得到 pid 值) 4. 若 fork 成功 (pid == 0),**啟動 SystemServer 進程** ```java= // /internal/os/ZygoteInit.java private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) { ... // 1. hardcode 指令參數,之後會分析使用這些指令 String[] args = { // 用戶 id "--setuid=1000", // 群組 id "--setgid=1000", // 擁有的群組 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023," + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011", "--capabilities=" + capabilities + "," + capabilities, "--nice-name=system_server", "--runtime-args", "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT, // 進程名稱 "com.android.server.SystemServer", }; ZygoteArguments parsedArgs; int pid; try { ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args); try { // 2. ZygoteArguments 分析 cmd parsedArgs = ZygoteArguments.getInstance(commandBuffer); } catch (EOFException e) { throw new AssertionError("Unexpected argument error for forking system server", e); } commandBuffer.close(); ... 省略部分 // 3. fork 一個新進程 pid = Zygote.forkSystemServer( parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids, parsedArgs.mRuntimeFlags, null, parsedArgs.mPermittedCapabilities, parsedArgs.mEffectiveCapabilities); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } /* For child process */ // pid == 0 代表成功 fork 出子進程 if (pid == 0) { // 目前子進程是 SystemServer 進程 // 如果有備用 Zygote 則進行等待 if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } // 由於 已經 fork 出一個新的進程,所以這個是關閉 SystemServer 的 Socket zygoteServer.closeServerSocket(); // 4. 啟動 System Server 進程 // @ 分析 handleSystemServerProcess return handleSystemServerProcess(parsedArgs); } // Parent Process (Zygote) 就是走這裡,返回 null return null; } ``` > ![](https://i.imgur.com/9BMjRKu.png) ### nativeForkSystemServer - 真正 fork 進程 * 透過 [**Zygote**](https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/com/android/internal/os/Zygote.java)#forkSystemServer 最終會呼叫到 system call fork,真正 fork SystemServer 進程 ```java= // /os/Zygote.java static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) { ZygoteHooks.preFork(); int pid = nativeForkSystemServer( uid, gid, gids, runtimeFlags, rlimits, permittedCapabilities, effectiveCapabilities); // Set the Java Language thread priority to the default value for new apps. Thread.currentThread().setPriority(Thread.NORM_PRIORITY); ZygoteHooks.postForkCommon(); return pid; } private static native int nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities); ``` * nativeForkSystemServer 是 Native 方法,既然它是 Native 方法就有對應的 JNI 類,它的 JNI 實現是 [**com_android_internal_os_zygote.cpp**](https://android.googlesource.com/platform/frameworks/base/+/master/core/jni/com_android_internal_os_Zygote.cpp)。最終會透過 Linux systemcall 的 fork 參數進行複製 ```cpp= // /jni/com_android_internal_os_Zygote.cpp static const JNINativeMethod gMethods[] = { ... 省略部分 {"nativeForkSystemServer", "(II[II[[IJJ)I", (void*)com_android_internal_os_Zygote_nativeForkSystemServer}, } static jint com_android_internal_os_Zygote_nativeForkSystemServer( JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities, jlong effective_capabilities) { ... 省略部分 // 使用 Linux System call fork current process // 追尋 ForkCommon 函數 pid_t pid = zygote::ForkCommon(env, true, fds_to_close, fds_to_ignore, true); if (pid == 0) { SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities, effective_capabilities, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true, false, nullptr, nullptr, /* is_top_app= */ false, /* pkg_data_info_list */ nullptr, /* allowlisted_data_info_list */ nullptr, false, false); } else { ... } return pid; } pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server, const std::vector<int>& fds_to_close, const std::vector<int>& fds_to_ignore, bool is_priority_fork, bool purge) { ... 省略部分 // 呼叫 System call#fork pid_t pid = fork(); if (pid == 0) { if (is_priority_fork) { // 傳入是 false setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX); } else { setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN); } ... 省略部分 } return pid; } ``` > ![](https://i.imgur.com/JC7tKwT.png) ### handleSystemServerProcess - 啟動 SystemServer 進程 * [**ZygoteInit**](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/com/android/internal/os/ZygoteInit.java)#handleSystemServerProcess 做以下事情 1. 創建 or 取得類加載器 `PathClassLoader` 2. 透過 Native 方法 `nativeZygoteInit` 開啟 Binder 通訊 ```java= // ZygoteInit.java private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) { ... 省略部分 if (parsedArgs.mInvokeWith != null) { ... 省略部分 } else { // 1. 創建 PathClassLoader ClassLoader cl = getOrCreateSystemServerClassLoader(); if (cl != null) { // 設定當前線程的 Class Loader Thread.currentThread().setContextClassLoader(cl); } // @ 查看 靜態方法 zygoteInit return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion, parsedArgs.mDisabledCompatChanges, parsedArgs.mRemainingArgs, cl); } /* should never reach here */ } public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges, String[] argv, ClassLoader classLoader) { ... 省略 Debug 訊息 RuntimeInit.redirectLogStreams(); RuntimeInit.commonInit(); // 啟動 Binder 線程池 ZygoteInit.nativeZygoteInit(); // @ 查看 applicationInit 方法 return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv, classLoader); } private static native void nativeZygoteInit(); ``` 3. 透過 [**RuntimeInit**](https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/com/android/internal/os/RuntimeInit.java)#`applicationInit` 方法準備啟動 SystemServer 的 main 方法 ```java= // RuntimeInit.java protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges, String[] argv, ClassLoader classLoader) { ... 省略部分 final Arguments args = new Arguments(argv); // The end of of the RuntimeInit event (see #zygoteInit). Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); // Remaining arguments are passed to the start class's static main return findStaticMain(args.startClass, args.startArgs, classLoader); } ``` * MethodAndArgsCaller 是 [**RuntimeInit**](https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/com/android/internal/os/RuntimeInit.java) 的一個靜態內部類,主要再儲存要 main 的方法 & 傳入的參數,將其包裝 ```java= static class MethodAndArgsCaller implements Runnable { /** method to call */ private final Method mMethod; /** argument array */ private final String[] mArgs; public MethodAndArgsCaller(Method method, String[] args) { mMethod = method; mArgs = args; } public void run() { try { mMethod.invoke(null, new Object[] { mArgs }); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { Throwable cause = ex.getCause(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } throw new RuntimeException(ex); } } } ``` * 最終會返回到 ZygoteInit#main 方法,**並運行 App 進程的 main 方法**,到這邊為止 ZygoteInit 結束任務 ```java= // /android/internal/os/ZygoteInit.java public static void main(String[] argv) { ... try { ... 省略部分 if (startSystemServer) { // 返回的 Runnable 就是 MethodAndArgsCaller Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); // {@code r == null} in the parent (zygote) process, and {@code r != null} in the // child (system_server) process. if (r != null) { // 執行 SystemServer 的 main 方法 r.run(); // 直接執行 // fork SystemServer 成功後直接跳出 (跳出後會先跑到 finally) return; } } } catch (Throwable ex) { Log.e(TAG, "System zygote died with exception", ex); throw ex; } finally { // 再次檢查如果有尚未關閉的 Socket 則關閉 if (zygoteServer != null) { zygoteServer.closeServerSocket(); } } ... } ``` ## Zygote Fork APP 進程 這是接續著 runSelectLoop 函數中的內容繼續分析, **繼續分析 APP fork 出的過程 (不是 init -> Zygote,而是 Zygote -> APP)** :::success fork app 關鍵方法名: **forkAndSpecialize** ::: * 從 [**Zygote.forkAndSpecialize**](https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/com/android/internal/os/Zygote.java#334) 開始看,該函數是真正 APP fork 進程的入口,主要分為 `preFork`、`nativeForkAndSpecialize`、`postForkCommon` 三種 Fork 步驟 ```java= // /core/java/com/android/internal/os/Zygote.java static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList, boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) { // 1. 完成堆空間的初始化 ZygoteHooks.preFork(); // 2. 真正孵化進程 // 調用 Linux System call : fork int pid = nativeForkAndSpecialize( uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp, pkgDataInfoList, allowlistedDataInfoList, bindMountAppDataDirs, bindMountAppStorageDirs); if (pid == 0) { ... } // Set the Java Language thread priority to the default value for new apps. Thread.currentThread().setPriority(Thread.NORM_PRIORITY); // 3. ZygoteHooks.postForkCommon(); return pid; } ``` :::info * nativeForkAndSpecialize 的實現在 [**com_android_internal_os_Zygote.cpp**](https://android.googlesource.com/platform/frameworks/base/+/master/core/jni/com_android_internal_os_Zygote.cpp) ::: ### [preFork](https://android.googlesource.com/platform/libcore/+/master/dalvik/src/main/java/dalvik/system/ZygoteHooks.java#134) - 分配堆空間 * 該函數的實現在 [**ZygoteHooks.java**](https://android.googlesource.com/platform/libcore/+/master/dalvik/src/main/java/dalvik/system/ZygoteHooks.java) 中 ```java= // /java/dalvik/system/ZygoteHooks.java public static void preFork() { Daemons.stop(); // 呼叫 Native 本地函數 token = nativePreFork(); waitUntilAllThreadsStopped(); } private static native long nativePreFork(); // 本地來分配堆空間 ``` * Native (nativePreFork 方法) 具體實踐在 [**dalvik_system_ZygoteHooks.cc**](https://android.googlesource.com/platform/art/+/master/runtime/native/dalvik_system_ZygoteHooks.cc) 的 [**ZygoteHooks_nativePreFork**](https://android.googlesource.com/platform/art/+/master/runtime/native/dalvik_system_ZygoteHooks.cc#253) 方法 ```java= // /dalvik_system_ZygoteHooks.cc#253 static jlong ZygoteHooks_nativePreFork(JNIEnv* env, jclass) { Runtime* runtime = Runtime::Current(); CHECK(runtime->IsZygote()) << "runtime instance not started with -Xzygote"; // 完成堆空間的初始操作 runtime->PreZygoteFork(); return reinterpret_cast<jlong>(ThreadForEnv(env)); } ``` > ![](https://i.imgur.com/JhFFCH5.png) ### nativeForkAndSpecialize - 真正 fork 進程 * 從名稱上就可以知道使用 Native 函數 ```java= // /java/dalvik/system/ZygoteHooks.java private static native int nativeForkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList, boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs); ``` * JNI 在 [**com_android_internal_os_Zygote.cpp**](https://android.googlesource.com/platform/frameworks/base/+/master/core/jni/com_android_internal_os_Zygote.cpp) 實現,在這裡會 ^1^ **真正 Fork APP 進程**、^2^ **呼叫 callPostForkChildHooks 函數(孵化進程後續的行為)** ```java= // /jni/com_android_internal_os_Zygote.cpp static const JNINativeMethod gMethods[] = { {"nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/" "String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)I", (void*)com_android_internal_os_Zygote_nativeForkAndSpecialize}, ... 省略部分 } static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app, jobjectArray pkg_data_info_list, jobjectArray allowlisted_data_info_list, jboolean mount_data_dirs, jboolean mount_storage_dirs) { // 開始 Fork APP 進程 pid_t pid = zygote::ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore,true); if (pid == 0) { SpecializeCommon(... /*省略參數*/); } return pid; } static void SpecializeCommon(... /*省略參數*/) { ... 省略部分 // 呼叫 callPostForkChildHooks 函數 env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags, is_system_server, is_child_zygote, managed_instruction_set); } pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server, const std::vector<int>& fds_to_close, const std::vector<int>& fds_to_ignore, bool is_priority_fork, bool purge) { SetSignalHandlers(); ... 省略部分 pid_t pid = fork(); // 1. 真正 Fork 出進程 if (pid == 0) { if (is_priority_fork) { setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX); } else { setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN); } // The child process. PreApplicationInit(); ... 省略部分 } else { ALOGD("Forked child process %d", pid); } // We blocked SIGCHLD prior to a fork, we unblock it here. UnblockSignal(SIGCHLD, fail_fn); return pid; } ``` :::info 到目前為止,是底層 Linux Fork 出新進程,尚未碰到應用程式邏輯 (下面小節分析) ::: > ![](https://i.imgur.com/IQPOnTp.png) ### handleChildProc - 啟動 APP 進程 * 在 forkAndSpecialize 完成後,繼續執行 **runSelectLoop** 方法 * 在上面 Linux 孵化出新進程後,後續的處理跳回到 ZygoteConnection#processCommand 函數,接續 **使用 `handleChildProc` 方法處理應用程式響應** ```java= // /internal/os/ZygoteConnection.java // 複習一下... Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) { ZygoteArguments parsedArgs; try (ZygoteCommandBuffer argBuffer = new ZygoteCommandBuffer(mSocket)) { while (true) { pid = Zygote.forkAndSpecialize(.../*省略參數*/) try { if (pid == 0) { // fork 成功返回 0 // in child zygoteServer.setForkChild(); zygoteServer.closeServerSocket(); IoUtils.closeQuietly(serverPipeFd); serverPipeFd = null; // @ 處理應用程式響應 return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote); } else { // in parent IoUtils.closeQuietly(childPipeFd); childPipeFd = null; handleParentProc(pid, serverPipeFd); return null; } } finally { IoUtils.closeQuietly(childPipeFd); IoUtils.closeQuietly(serverPipeFd); } } } ... 省略部分 } ``` * handleChildProc 方法:一般來說 `parsedArgs.mInvokeWith` 為空,並準備進入啟動進程 (這裡會區分是不是 Zygote 進程) | fork 種類 | 處理方法 | | -------- | -------- | | 一般 APP | ZygoteInit.zygoteInit | | Zygote 進程 | ZygoteInit.childZygoteInit | ```java= // /internal/os/ZygoteConnection.java private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor pipeFd, boolean isZygote) { // 運行到這時,已經關閉 2 個 Zygote Socket,並用 `/dev/null` 替代 // 因為一般進程不需要 Socket 連接 closeSocket(); Zygote.setAppProcessName(parsedArgs, TAG); // End of the postFork event. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); if (parsedArgs.mInvokeWith != null) { WrapperInit.execApplication(parsedArgs.mInvokeWith, parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion, VMRuntime.getCurrentInstructionSet(), pipeFd, parsedArgs.mRemainingArgs); // Should not get here. throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned"); } else { if (!isZygote) { return // 啟動子進程 (一般 APP) // @ 查看 zygoteInit ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion, parsedArgs.mDisabledCompatChanges, parsedArgs.mRemainingArgs, null /* classLoader */); } else { // 啟動 Zygote 進程 return ZygoteInit.childZygoteInit( parsedArgs.mRemainingArgs /* classLoader */); } } } ``` > ![](https://i.imgur.com/5c8S8yM.png) :::success * 傳統 Linux fork、Zygote fork 差異 ? 傳統 Linux 內核需要 **fork+exec**,**而 Zygote 並不會執行 exec** (因為它需要用到 ZygoteInit 的 JVM、JNI... 的初始化) 所以在某些情況下會造成障礙 (eg. valgrind 無法監測內存洩漏),而 Android 系統為了該情況特別實現 Wrapper 類,並通過 **parsedArgs.mInvokeWith 來控制** ::: ```java= // /os/ZygoteInit.java public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges, String[] argv, ClassLoader classLoader) { ... 省略部分 RuntimeInit.commonInit(); // 設定時區,鍵盤資訊等等... ZygoteInit.nativeZygoteInit(); // 啟動 Binder (之後分析) // @ 查看 applicationInit return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv, classLoader); } // ------------------------------------------------------------------ // RuntimeInit.java protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges, String[] argv, ClassLoader classLoader) { ... 省略部分 // @ 查看 findStaticMain return findStaticMain(args.startClass, args.startArgs, classLoader); } protected static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) { Class<?> cl; try { // App 來講就是啟動 ActivityThread cl = Class.forName(className, true, classLoader); } /* 省略 catch 拋出 */ Method m; try { m = cl.getMethod("main", new Class[] { String[].class }); } /* 省略 catch */ int modifiers = m.getModifiers(); if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) { throw new RuntimeException( "Main method is not public and static on " + className); } /* * This throw gets caught in ZygoteInit.main(), which responds * by invoking the exception's run() method. This arrangement * clears up all the stack frames that were required in setting * up the process. */ return new MethodAndArgsCaller(m, argv); } ``` * MethodAndArgsCaller 是 [**RuntimeInit**](https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/com/android/internal/os/RuntimeInit.java) 的一個靜態內部類,主要再儲存要 main 的方法、傳入的參數 ```java= static class MethodAndArgsCaller implements Runnable { /** method to call */ private final Method mMethod; /** argument array */ private final String[] mArgs; public MethodAndArgsCaller(Method method, String[] args) { mMethod = method; mArgs = args; } public void run() { try { mMethod.invoke(null, new Object[] { mArgs }); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { Throwable cause = ex.getCause(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } throw new RuntimeException(ex); } } } ``` * 最終會返回到 ZygoteInit#main 方法,**並運行 App 進程的 main 方法**,到這邊為止 ZygoteInit 結束任務 ```java= // /android/internal/os/ZygoteInit.java public static void main(String[] argv) { ... try { ... 省略部分 // 進入循環 Loop,等待 AMS 的請求 !! caller = zygoteServer.runSelectLoop(abiList); } catch (Throwable ex) { Log.e(TAG, "System zygote died with exception", ex); throw ex; } finally { if (zygoteServer != null) { zygoteServer.closeServerSocket(); } } // caller 是一個 Runnable 類型 (MethodAndArgsCaller 類) if (caller != null) { caller.run(); // 其內容包裝的是 fork 出來的靜態 main 方法 } } ``` ## Binder 線程池 在應用 APP 創建的過程中會啟動 Binder 線程池,不管是 SystemServer or 一般 APP 進程,都會執行 Binder 線程池啟動 ### Zygote fork 時啟動 Binder * 複習一下 Zygote 收到 AMS 通知後,fork App 進程後,就會呼叫 `zygoteInit` 函數,並在這裡啟動 Binder (進入 JNI) ```java= public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges, String[] argv, ClassLoader classLoader) { ... 省略部分 // @ 查看 nativeZygoteInit ZygoteInit.nativeZygoteInit(); return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv, classLoader); } // 調用 JNI 函數 private static native void nativeZygoteInit(); ``` ### 啟動 Binder 線程池 - startThreadPool :::info App 主要使用 [nativeZygoteInit](https://android.googlesource.com/platform/frameworks/base/+/master/core/jni/AndroidRuntime.cpp#19),最終仍會透過 `startThreadPool` 啟動 BinderThread ::: * 以 SystemServer 為例:SystemServer 與一般 APP 在不同的進程,若要通訊就需要通過 Binder 通訊機制,所以 **ZygoteInit 透過 `nativeZygoteInit` 來開啟 SystemServer 的 Binder 通訊** ```cpp= // AndroidRuntime.cpp int register_com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env) { const JNINativeMethod methods[] = { { "nativeZygoteInit", "()V", (void*) com_android_internal_os_ZygoteInit_nativeZygoteInit }, }; return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit", methods, NELEM(methods)); } // 自身對象 static AndroidRuntime* gCurRuntime = NULL; static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz) { // onZygoteInit 是抽象方法 gCurRuntime->onZygoteInit(); } // ------------------------------------------------------------------------ // /jni/include/android_runtime/AndroidRuntime.h virtual void onZygoteInit() { } ``` :::info * AndroidRuntime 成員 **gCurRuntime** 的初始化,在 AndroidRuntime 建構函數中,而 init 進程 `app_main#main` 在一開始就會創建 AndroidRuntime 對象 ```cpp= // /cmds/app_process/app_main.cpp int main(int argc, char* const argv[]) { ... // argv[0] 是啟動名稱,eg. zygote AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); int i; ... } ``` AndroidRuntime 建構函數就賦予 gCurRuntime 為自身對象 ```cpp= // AndroidRuntime.cpp AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) : mExitWithoutCleanup(false), mArgBlockStart(argBlockStart), mArgBlockLength(argBlockLength) { ... assert(gCurRuntime == NULL); // one per process // 所有的 App 進程的 gCurRuntime 都是 AppRuntime gCurRuntime = this; } ``` ::: * AndroidRuntime#onZygoteInit 是抽象方法,它的實現類是 [**AppRuntime**](https://android.googlesource.com/platform/frameworks/base/+/master/cmds/app_process/app_main.cpp) (**這也是 AppRuntime 的特點,它的 `onZygoteInit` 用來初始化 BinderPool**) ```java= // app_main.cpp class AppRuntime : public AndroidRuntime { public: ... 省略部分 virtual void onZygoteInit() { // 每個進程中只會有一個 ProcessState 實例 sp<ProcessState> proc = ProcessState::self(); ALOGV("App process: starting thread pool.\n"); // 準備分析 startThreadPool 方法 proc->startThreadPool(); } } ``` * Binder 線程池先了解到這邊,主要是要知道透過 `startThreadPool` 方法就可以創建一個 Thread 並與其他進程通訊 :::info * 每個進程都只能透過 ProcessState#`startThreadPool` 開啟一次線程池 ::: ### 啟動 Binder ThreadPool - startThreadPool * ProcessState#**startThreadPool 函數** * [**ProcessState**](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/ProcessState.cpp) 啟動 PoolThread 線程池:這裡需要 ^1^ 為線程池取名,^2^ 產生 PoolThread (線程池) 對象,^3^ 在 [**Threads**](https://android.googlesource.com/platform/frameworks/native/+/jb-dev/libs/utils/Threads.cpp)#run 函數最後會呼叫回 PoolThread#`threadLoop` 函數 :::success * 創建一個 Thread 無限循環與 Binder 通訊 PoolThread#`threadLoop` 函數 會將剛剛創建的 Thread 加入 BinderThread,與 BinderDriver 通訊 ::: ```cpp= // /binder/ProcessState.cpp void ProcessState::startThreadPool() { AutoMutex _l(mLock); if (!mThreadPoolStarted) { mThreadPoolStarted = true; // 啟動線程池的 flag // spawn 產卵 spawnPooledThread(true); // 往下分析,產生一個線程池,注意參數為 true } } void ProcessState::spawnPooledThread(bool isMain) { if (mThreadPoolStarted) { // 1. 為了該線程池取名 String8 name = makeBinderThreadName(); ALOGV("Spawning new pooled thread, name=%s\n", name.string()); // 2. 產生 PoolThread (線程池) 對象 sp<Thread> t = sp<PoolThread>::make(isMain); @ 查看 run t->run(name.string()); } } // 線程池是 Thread 的子類 class PoolThread : public Thread { public: explicit PoolThread(bool isMain) : mIsMain(isMain) { } protected: virtual bool threadLoop() { // @ 最終會呼叫 joinThreadPool 方法 IPCThreadState::self()->joinThreadPool(mIsMain); return false; } const bool mIsMain; }; ``` * [**Thread**](https://cs.android.com/android/platform/superproject/+/master:system/core/libutils/Threads.cpp)#run 函數:創建一個 Thread,並在創建完 Thread 後調用 `threadLoop` 函數,這時就為 **調用到 `joinThreadPool` 函數** ```cpp= // Threads.cpp status_t Thread::run(const char* name, int32_t priority, size_t stack) { ... bool res; if (mCanCallJava) { // @ 查看函數指標 _threadLoop res = createThreadEtc(_threadLoop, this, name, priority, stack, &mThread); } else { // @ 查看函數指標 _threadLoop res = androidCreateRawThreadEtc(_threadLoop, this, name, priority, stack, &mThread); } if (res == false) { ...啟動失敗處理 } return NO_ERROR; } // 函數指標 int Thread::_threadLoop(void* user) { Thread* const self = static_cast<Thread*>(user); ... bool first = true; do { bool result; if (first) { ... if (result && !self->exitPending()) { // 呼叫回 PoolThread 的 threadLoop result = self->threadLoop(); } } else { // 呼叫回 PoolThread 的 threadLoop result = self->threadLoop(); } ... } while(strong != 0); return 0; } ``` ### 進入 Binder ThreadPool - joinThreadPool * IPCThreadState#**joinThreadPool 函數**:進入循環通訊 * [**IPCThreadState**](https://android.googlesource.com/platform/frameworks/native/+/jb-dev/libs/binder/IPCThreadState.cpp) **的 ==joinThreadPool 函數==**:這個函數就會不斷的循環跟 Binder 驅動交流,如同 SM 中的 binder_loop 函數([**talkWithDriver 參考另外一篇**](https://hackmd.io/_8ne10VrSK-mK6nlyxL5RQ?view#IPCThreadState---transact-%E5%82%B3%E9%80%81%E5%91%BD%E4%BB%A4)) * **executeCommand 函數** 則是執行接收的命令,之後分析 ```cpp= // /libs/binder/IPCThreadState.cpp void IPCThreadState::joinThreadPool(bool isMain) // 從 PoolThread 傳近來的參數是 true { // 是否進入主循環 mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); ... status_t result; do { int32_t cmd; ... // 若 ioctl 無資料則會進入休眠 result = talkWithDriver(); // binder_thread_write & read 與 binder 驅動通訊 // 判斷接收資料是否錯誤 if (result >= NO_ERROR) { size_t IN = mIn.dataAvail(); // 是否有數據可讀 if (IN < sizeof(int32_t)) continue; cmd = mIn.readInt32(); ... // 分析接收到的 Command result = executeCommand(cmd); // 執行對應 cmd } set_sched_policy(mMyThreadId, SP_FOREGROUND); // Let this thread exit the thread pool if it is no longer // needed and it is not the main process thread. if(result == TIMED_OUT && !isMain) { break; } } while (result != -ECONNREFUSED && result != -EBADF); ... mOut.writeInt32(BC_EXIT_LOOPER); talkWithDriver(false); } ``` :::info 這一步結束後,該 APP 進程就準備好,可以跟 BinderDriver 通訊 ::: ## Appendix & FAQ :::info ::: ###### tags: `Android 系統`