---
title: 'Android 啟動過程 - Zygote 進程'
disqus: kyleAlien
---
Zygote 進程
===
[**init 進程**](https://hackmd.io/pJpAeKAeRea0VIW3oI-mXw?view) 會透過分析 .rc 檔案來 `fork` + `execv` Zygote 進程
## OverView of Content
[TOC]
## 系統進程之間 - 關係
這個章節著重講解的是 **++Zygote 進程++**,但了解它的來源也是相當重要的,請參考下圖
> 
### 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)
:::
> 
* 從 `init.rc` 被 init 進程分析後,觸發 `app_main.cpp` 的流程圖
> 
### 透過 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)
> 
### 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,
},
}
```
> 
## Zygote 啟動過程
`app_main.cpp#main` 中,主要做的就是參數解析 (**解析 `rc 檔` 傳入的參數**),並 **分成 ++2 種++ 啟動模式**
1. Zygote 模式: 初始化 Zygote 進程
2. Application 模式: 啟動普通的 APP 進程 (傳遞的參數有 class name、class 參數)
而上述兩者最終都會執行 **`AndroidRuntime#start` 方法**
> 
### 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");
}
```
> 
### [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) 技術
:::
> 
### [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 代表成功,其他則是失敗
:::
> 
### 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==**
>
> 
:::
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;
}
```
> 
### 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;
}
```
> 
### 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));
}
```
> 
### 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 出新進程,尚未碰到應用程式邏輯 (下面小節分析)
:::
> 
### 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 */);
}
}
}
```
> 
:::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 系統`