1. 概述
在 Android 系統中,所有的應用程序以及系統服務進程 SystemService 都是由 zygote 進程孕育 (fork)出來的。zygote 進程的作用可以概括爲以下三點:
- 創建 java 虛擬機,加載系統資源
- 應用程序啓動過程中負責 fork 出子進程
在 Android 應用程序啓動時,ActivityManagerService 會通過 socket 與 zygote 進程進行通信,請求它 fork 一個子進程出來作爲這個即將要啓動的應用程序的進程。 - 系統重要服務進程 SystemService 的孕育者
Android 系統中非常重要的系統服務進程 SystemServer 也是 zygote 在啓動過程中 fork 出來的。
2. zygote 分析
2.1 啓動過程分析
我們知道 Android 系統是基於 Linux 內核的,而在 Linux 系統中,所有的進程都是 init 進程的子進程,zygote 進程也不例外,它是由 init 進程創建的。
File:system/core/rootdir/init.rc
import /init.${ro.zygote}.rc
File:system/core/rootdir/init.zygote32.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
- 關鍵字 service 爲:創建一個名爲 zygote 的進程,這個 zygote 進程要執行的程序是 /system/bin/app_process,後面是傳給 app_process 的參數。
- socket 關鍵字表示這個 zygote 進程需要一個名稱爲 zygote 的 socket 資源,這樣系統在我們就可以在 /dev/socket 目錄下看到一個名爲 zygote 的文件,這裏的 socket 主要用於本地進程間通信。ActivityManagerService 就是通這個 socket 來和 zygote 進程通信請求 fork 一個應用程序進程。
- 後面的 onrestart 表示這個 zygote 進程重啓時需要執行的命令。
而進程 app_process 的源碼位置在:platform/frameworks/base/cmds/app_process/app_main.cpp
這個函數由兩種啓動模式:
- 一種是 zygote 模式,也就是初始化 zygote 進程,傳遞的參數有 --start-system-server、 --socket-name=zygote,前者表示啓動SystemServer,後者指定socket的名稱
- 一種是 application 模式,也就是啓動普通應用程序,傳遞的參數有 class 名字以及 class 帶的參數
兩者最終都是調用 AppRuntime 對象的 start 函數,加載 ZygoteInit 或 RuntimeInit 兩個Java類,並將之前整理的參數傳入進去。
由於本篇講的是zygote進程啓動流程,因此接下來我只講解ZygoteInit的加載.
int main(int argc, char* const argv[])
{
...
// 構建 AppRuntime 對象,並將參數 (-Xzygote) 傳遞進去
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// Process command line arguments
// ignore argv[0]
argc--;
argv++;
// 所有在"--"後面或者非"-"開頭的參數都會被傳入vm
// 所謂一個特例,在 spaced_commands 變量中定義的參數會被傳入vm
const char* spaced_commands[] = { "-cp", "-classpath" };
// Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
bool known_command = false;
...
省略代碼
通過 runtime.addOption 初始化參數集合
這邊直接跳過
...
// Parse runtime arguments. Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
// 跳過一個參數,之前跳過了 -Xzygote,這裏繼續跳過 /system/bin,就是所謂的 parent dir
++i; // Skip unused "parent dir" argument.
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) { // 表示是 zygote 啓動模式
zygote = true;
niceName = ZYGOTE_NICE_NAME; // 根據平臺可能是 zygote64 或 zygote
} else if (strcmp(arg, "--start-system-server") == 0) { // 是否開啓 SystemService
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) { // application 啓動模式
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) { // 進程別名
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) { // application啓動的class
className.setTo(arg);
break;
} else {
--i;
break;
}
}
Vector<String8> args;
if (!className.isEmpty()) {
// className 不爲空表示是 application 啓動模式
// 這裏不做分析
...
} else {
// 表示處在 zygote 啓動模式
// 新建Dalvik的緩存目錄.
maybeCreateDalvikCache();
if (startSystemServer) {
args.add(String8("start-system-server"));
}
//加入--abi-list=參數
char prop[PROP_VALUE_MAX];
if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
ABI_LIST_PROPERTY);
return 11;
}
String8 abiFlag("--abi-list=");
abiFlag.append(prop);
args.add(abiFlag);
// In zygote mode, pass all remaining arguments to the zygote
// main() method.
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}
// 設置進程別名
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
if (zygote) {
//如果是zygote啓動模式,則加載ZygoteInit
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
}
我們看到,在最後調用的是 runtime.start 函數,這個就是要啓動虛擬機了,接下來我們分析 start 函數
2.2 AppRuntime 分析
AppRuntime 類的聲明和實現均在 app_main.cpp 中,它是由 AndroidRuntime 類派生出來的,AppRuntime 重載了 onStart、onZygoteInit、onExit 等一些重要的方法。
前面調用的 start 方法實現在基類 AndroidRuntime 中,前半部分主要是初始化JNI,然後創建虛擬機,註冊一些JNI函數
File:platform/frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
... // 日誌打印,獲取ANDROID_ROOT環境變量
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
// ① 創建虛擬機
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env); //表示虛擬創建完成時回調的方法
/*
* Register android functions.
*/
// ② 註冊 JNI 函數
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
... //③ JNI 方式調用 ZygoteInit 類的 main 函數
}
上面的分析中,關鍵點①、②、③共同組成了 Android 系統中 Java 世界的三部曲。
1. 創建虛擬機 startVm
這個函數沒有特別之處,就是調用JNI的虛擬機創建函數,但是創建虛擬機時的一些參數是在 startVm 中確定的,其實就是從各種系統屬性中讀取一些參數,然後通過 addOption 設置到 AndroidRuntime 的 mOptions 數組中存起來,代碼如下:
File:platform/frameworks/base/core/jni/AndroidRuntime.cpp
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
// 調用 JNI_CreateJavaVM 創建虛擬機,pEnv 返回當前線程的 JniEnv 變量
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
ALOGE("JNI_CreateJavaVM failed\n");
return -1;
}
return 0;
}
2. 註冊 JNI 函數 startReg
前面是如何創建虛擬機,下一步需要給虛擬機註冊一些 JNI 函數,正式因爲後續 Java 世界用到的一些函數時採用 native 方法實現的,所以才必須提前註冊這些函數
File:platform/frameworks/base/core/jni/AndroidRuntime.cpp
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
ATRACE_NAME("RegisterAndroidNatives");
// 設置 Thread 類的線程創建函數爲 javaCreateThreadEtc
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
ALOGV("--- registering native functions ---\n");
// 創建一個 200 容量的局部引用作用域
env->PushLocalFrame(200);
// 註冊 Jni 函數
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL); //釋放局部引用作用域
//createJavaThread("fubar", quickTest, (void*) "hello");
return 0;
}
register_jni_procs是主要的 JNI 註冊函數
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
for (size_t i = 0; i < count; i++) {
if (array[i].mProc(env) < 0) {
#ifndef NDEBUG
ALOGD("----------!!! %s failed to load\n", array[i].mName);
#endif
return -1;
}
}
return 0;
}
mProc 就是爲 Java 類註冊了 JNI 函數
3. 反射調用 ZygoteInit 類的 main 函數
虛擬機已創建好,JNI函數也已註冊,下一步就是通過CallStaticVoidMethod了,通過這個函數真正進入 Java 世界。
這個 Java 世界的入口就是 CallStaticVoidMethod 最終調用的 com.android.internal.os.ZygoteInit 的 main 函數。
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
...
// ① 創建 Socket,通過這個 Socket 與 ActivityManagerService 通信
zygoteServer.registerServerSocket(socketName);
...
// ② 預加載資源
preload(bootTimingsTraceLog);
...
if (startSystemServer) {
// ③ fork 出 SystemService
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
if (r != null) {
r.run();
return;
}
}
......
zygoteServer.runSelectLoop(abiList);
......
}
建立 IPC 通信服務端 - registerServerSocket
先分析主體的框架,首先創建了一個 ZygoteServer 類,並 registerServerSocket 創建一個 Socket,這個Socket 將 listen 並 accept Client
它將作爲服務端來和客戶端的 ActivityManagerService 進行通信來 fork 出子進程。
預加載類和資源 - preload
首先看 preloadClass
File:ZygoteInit.java
private static void preloadClasses() {
final VMRuntime runtime = VMRuntime.getRuntime();
InputStream is;
try {
// 預加載類的信息存儲在 PRELOADED_CLASSED 中(/system/etc/preloaded-classes)
is = new FileInputStream(PRELOADED_CLASSES);
} catch (FileNotFoundException e) {
Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
return;
}
... // 統計工作
try {
BufferedReader br
= new BufferedReader(new InputStreamReader(is), 256);
int count = 0;
String line;
while ((line = br.readLine()) != null) {
// Skip comments and blank lines.
line = line.trim();
if (line.startsWith("#") || line.equals("")) {
continue;
}
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, line);
try {
if (false) {
Log.v(TAG, "Preloading " + line + "...");
}
// Load and explicitly initialize the given class. Use
// Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups
// (to derive the caller's class-loader). Use true to force initialization, and
// null for the boot classpath class-loader (could as well cache the
// 通過 JAVA 反射來加載類
// class-loader of this class in a variable).
Class.forName(line, true, null);
count++;
} catch (ClassNotFoundException e) {
}
}
Log.i(TAG, "...preloaded " + count + " classes in "
+ (SystemClock.uptimeMillis()-startTime) + "ms.");
} catch (IOException e) {
Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
} finally {
... // 掃尾工作
}
}
preload_class 文件由 framework/base/tools/preload 工具生成,它判斷每個類加載的時間是否大於1250微秒,超過就寫入 preload_class 文件,最後由 zygote 進行預加載。
preloadClass 執行的時間比較長,這也是andorid啓動慢的原因,可以在此進行開機速度優化
preloadResource 預加載的原理很簡單,就是在 zygote 進程啓動後將資源讀取出來,保存到 Resources 一個全局靜態變量中,下次讀取系統資源的時候優先從靜態變量中查找
啓動 SystemService —— forkSystemServer
第三個關鍵點是 startSystemService,這個函數會創建 Java 世界中傳統 Service 所駐留的進程 system_service,該進程是 framework 的核心。
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
...
// 設置參數
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
/* Request to fork the system server process */
// fork 出一個子進程,這個子進程就是 systemSevice
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
if (pid == 0) {
// fork 成功,開啓一些預備工作
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket();
return handleSystemServerProcess(parsedArgs);
}
return null;
}
Zygote.forkSystemServer() 創建一個系統服務進程,進程創建成功後返回 pid 爲 0,由於此處生成的新進程和 Zygote 進程一模一樣,也就是說這個新進程中同樣包含了剛纔創建的 Socket,但是該 Socket 在此處無效,因此要將其關閉。接下來調用 handleSystemServerProcess() 處理剛纔新建的進程即 SystemServer 進程,需要注意此時已經工作在 SystemServe r進程中
有求必應之等待請求 —— runSelectLoop
前面一個關鍵點是 registZygotSocket 註冊了一個用於 IPC 的 Socket,它的用途在這個函數中能體現出來,這個函數監聽客戶端的請求
/**
* Runs the zygote process's select loop. Accepts new connections as
* they happen, and reads commands from connections one spawn-request's
* worth at a time.
*/
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
// 新客戶端連接請求,充當服務端 Socket
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
try {
ZygoteConnection connection = peers.get(i);
final Runnable command = connection.processOneCommand(this);
if (mIsForkChild) {
// We're in the child. We should always have a command to run at this
// stage if processOneCommand hasn't called "exec".
if (command == null) {
throw new IllegalStateException("command == null");
}
return command;
} else {
// We're in the server - we should never have any commands to run.
if (command != null) {
throw new IllegalStateException("command != null");
}
// We don't know whether the remote side of the socket was closed or
// not until we attempt to read from it from processOneCommand. This shows up as
// a regular POLLIN event in our regular processing loop.
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(i);
fds.remove(i);
}
}
} catch (Exception e) {
...
}
}
}
}
}
- 處理客戶端連接和客戶請求,其中客戶在 zygote 中用 ZygoteConnection 對象來表示
- 客戶的請求在函數 processOneCommand 中處理
3. 總結
zygote 是 Android系統中創建 Java 世界的盤古,它創建第一個 Java 虛擬機,同時它又是女媧,繁殖了 framework 的核心 system_server 進程
- 第一天,創建 AppRuntime 對象,並調用他的 start,此後的活動由 AppRuntime 控制
- 第二天,調用 startVm 創建 Java 虛擬機,然後調用 startReg 來註冊 JNI 函數
- 第三天,通過 JNI 調用 com.android.internal.os.ZygoteInit 類的 main 函數,進入 Java 世界,但這個世界剛開始啥也沒有
- 第四天,調用 registerZygoteSocket,通過這個函數,它可以響應子孫後代的請求,同時 zygote 調用 preloadClasses 和 preloadResources,爲Java世界添磚加瓦
- 第五天,zygote 覺得自己的工作壓力大了,便通過調用 startSystemServer 分裂一個子進程 system_server 來爲 java 世界服務
- 第六天,zygote 調用 runSelectLoop – 等待並處理來自客戶的消息,後便睡去
以後的日子裏,zygote 隨時守護在我們周圍,當接收子孫後代的請求後,它會隨時醒來爲它們工作。