在Android系統中,DVM、ART、應用程序進程和SystemServer進程都是由Zygote進程創建的,因此Zygote又稱爲“孵化器”。它是通過fork的形式來創建應用程序進程和SystemServer進程,由於Zygote進程在啓動時會創建一個DVM或者ART,因此通過fork而創建的應用程序進程和SystemServer進程可以在內部獲取一個DVM或ART的實例副本。
備註:本文將結合Android8.0的源碼看Zygote進程的啓動過程以及Zygote進程做了哪些重要工作。
1. Zygote進程啓動腳本
在init.rc中採用的是import類型語句來引入Zygote啓動腳本,這些啓動腳本都是由Android初始化語言來寫的:
import /init.${ro.zygote}.rc
可以看出:init.rc中不會直接引入一個固定的文件,而是根據屬性ro.zygote的內容來引入不同的文件。
從Android5.0開始,Android開始支持64位程序,Zygote就有了32位和64位的區別。所以這裏就用ro.zygote屬性來控制使用不同的Zygote啓動腳本,從而就啓動不同版本的Zygote進程。
ro.zygote屬性的值有如下四種:
-
init.zygote32.rc
-
init.zygote32_64.rc
-
init.zygote64.rc
-
init.zygote64_32.rc
這些Zygote啓動腳本都是放在system/core/rootdir/目錄下。
1.1 init.zygote32.rc
表示支持純32位程序,內容如下所示:
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
-
執行程序是app_process
-
classname爲main
-
如果audioserver、cameraserver、media、netd、wificond等進程終止時,Zygote進程會重啓。
1.2 init.zygote32_64.rc
表示既支持32位程序也支持64位程序,內容如下所示:
service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
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_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
priority -20
user root
group root readproc
socket zygote_secondary stream 660 root system
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks
可以發現,腳本中有兩個Service類型語句,說明會啓動兩個Zygote進程:
-
一個進程名爲:zygote;執行程序爲:app_process32,作爲主模式
-
另一個進程名爲:zygote_secondary;執行程序爲:app_process64,作爲輔模式
2. Zygote進程啓動過程
在《從源碼角度看Android系統init進程啓動過程》一文中可知:init啓動Zygote調用的是app_main.cpp的main函數中AppRuntime的start方法來啓動Zygote進程。
代碼路徑:frameworks/base/cmds/app_process/app_main.cpp
main函數如下:
int main(int argc, char* const argv[])
{
...省略...
//傳到的參數argv是“-Xzygote /system/bin --zygote --start-system-server”
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
//忽略第一個參數
argc--;
argv++;
...省略...
// 參數解析
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
++i;
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) { //註釋1
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) { //註釋2
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}
Vector<String8> args;
if (!className.isEmpty()) {
// 運行application或tool程序
args.add(application ? String8("application") : String8("tool"));
runtime.setClassNameAndArgs(className, argc - i, argv + i);
...省略...
} else {
//進入zygote模式,創建 /data/dalvik-cache路徑
maybeCreateDalvikCache();
if (startSystemServer) {
args.add(String8("start-system-server"));
}
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);
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}
//設置進程名
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
if (zygote) { //註釋3
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.");
}
}
註釋解析:
-
註釋1處判斷參數arg中是否包含了“–zygote”,如果包含了則說明main函數是運行在Zygote進程中。將參數zygote設置爲true;並給niceName賦值,64位系統nice_name爲zygote64、32位系統nice_name爲zygote
-
註釋2處判斷參數arg中是否包含了“–start-system-server”,如果包含了則說明main函數是運行在SystemServer進程中。將參數startSystemServer設置爲true。
-
註釋3出判斷zygote是否爲 true,如果爲true,就說明運行在Zygote進程中,然後就調用AppRuntime中的start函數
深入到AppRuntime中的start函數中:
代碼路徑:frameworks/base/core/jni/AndroidRuntime.cpp
start函數如下:
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
...省略...
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
//啓動java虛擬機
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
//爲java虛擬機註冊JNI方法
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
...省略...
//從app_main的main函數中可以傳過來的className是com.android.internal.os.ZygoteInit
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
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);
}
//將com.android.internal.os.ZygoteInit轉換爲com/android/internal/os/ZygoteInit
char* slashClassName = toSlashClassName(className);
//找到ZygoteInit
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
//找到ZygoteInit的main方法
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
//通過JNI調用ZygoteInit的main方法
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);
...省略...
}
從上面的註釋可以看出,start函數做了如下工作:
-
調用startVm函數來創建Java虛擬機
-
調用startReg函數爲Java虛擬機註冊JNI方法
-
將傳進來的參數com.android.internal.os.ZygoteInit轉換爲com/android/internal/os/ZygoteInit,並賦值給slashClassName
-
通過slashClassName找到ZygoteInit
-
通過JNI調用ZygoteInit的main方法
在通過JNI調用ZygoteInit的main方法後,Zygote就進入了Java框架層。
深入到ZygoteInit方法中:
代碼路徑:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
main函數如下:
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
...省略...
try {
...省略...
//創建一個Server端的Socket,socketName的值爲“zygote”
zygoteServer.registerServerSocket(socketName); //註釋1
// In some configurations, we avoid preloading resources and classes eagerly.
// In such cases, we will preload things prior to our first fork.
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
//預加載類和資源
preload(bootTimingsTraceLog); //註釋2
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
}
...省略...
//啓動SystemServer進程
if (startSystemServer) {
startSystemServer(abiList, socketName, zygoteServer); //註釋3
}
Log.i(TAG, "Accepting command socket connections");
//等待AMS請求
zygoteServer.runSelectLoop(abiList); //註釋4
zygoteServer.closeServerSocket();
} catch (Zygote.MethodAndArgsCaller caller) {
caller.run();
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
zygoteServer.closeServerSocket();
throw ex;
}
}
註釋解析:
-
註釋1處通過registerServerSocket方法來創建一個Server端的Socket,這個name爲zygote的Socket用於等待ActivityManagerService請求Zygote創建新的應用程序進程
-
註釋2預加載類和資源
-
註釋3啓動SystemServer進程
-
註釋4處調用ZygoteServer的runSelectLoop方法來等待AMS請求創建新的應用程序進程
綜上所述:ZygoteInit的main方法主要做了4件事:
-
創建一個Server端的Socket
-
預加載類和資源
-
啓動SystemServer進程
-
等待AMS請求創建新的應用程序進程
下面分別對這四件事跟蹤源碼分析下。
2.1 registerServerSocket
代碼路徑:frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
深入到registerServerSocket函數中:
void registerServerSocket(String socketName) {
if (mServerSocket == null) {
int fileDesc;
//拼接Socket的名稱
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; //註釋1
try {
//得到Socket的環境變量的值
String env = System.getenv(fullSocketName); //註釋2
//將Socket環境變量的值轉換爲文件描述符的參數
fileDesc = Integer.parseInt(env); //註釋3
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}
try {
//創建文件描述符
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
//創建服務器端的Socket
mServerSocket = new LocalServerSocket(fd); //註釋4
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
註釋解析:
-
註釋1拼接Socket的名稱,其中ANDROID_SOCKET_PREFIX的值爲“ANDROID_SOCKET_”,socketName的值是傳進來的“zygote”,因此fullSocketName的值爲“ANDROID_SOCKET_zygote”
-
註釋2處將fullSocketName轉換爲環境變量的值
-
註釋3將環境變量的值轉換爲文件描述符參數
-
註釋4創建LocalServerSocket,也就是服務器端的Socket
在Zygote進程將SystemServer進程啓動後,就會在這個服務器端的Socket上等待AMS請求Zygote進程來創建新的應用程序進程。
2.2 preload
代碼路徑:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
深入到preload函數中:
static void preload(BootTimingsTraceLog bootTimingsTraceLog) {
Log.d(TAG, "begin preload");
bootTimingsTraceLog.traceBegin("BeginIcuCachePinning");
beginIcuCachePinning();
bootTimingsTraceLog.traceEnd(); // BeginIcuCachePinning
bootTimingsTraceLog.traceBegin("PreloadClasses");
//預加載位於/system/etc/preloaded-classes文件中的類
preloadClasses();
bootTimingsTraceLog.traceEnd(); // PreloadClasses
bootTimingsTraceLog.traceBegin("PreloadResources");
預加載資源,包含drawable和color資源
preloadResources();
bootTimingsTraceLog.traceEnd(); // PreloadResources
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");
//預加載OpenGL
preloadOpenGL();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
//通過System.loadLibrary()方法,
//預加載"android","compiler_rt","jnigraphics"這3個共享庫
preloadSharedLibraries();
//預加載 文本連接符資源
preloadTextResources();
//僅用於zygote進程,用於內存共享的進程
WebViewFactory.prepareWebViewInZygote();
endIcuCachePinning();
warmUpJcaProviders();
Log.d(TAG, "end preload");
sPreloadComplete = true;
}
-
類加載,採用的是反射機制Class.forName()方法來加載。
-
加載的資源主要是com.android.internal.R.array.preloaded_drawables和com.android.internal.R.array.preloaded_color_state_lists,在應用程序中以com.android.internal.R.xxx開頭的資源,就是在此時由Zygote加載到內存中的。
zygote進程內加載了preload()方法中的所有資源,當需要fork新進程時,採用copy on write技術,如下圖所示:
從上圖可以看出在創建新進程時,會共享父進程Zygote地址空間。
2.3 startSystemServer
代碼路徑:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
深入到startSystemServer函數中:
private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer)
throws Zygote.MethodAndArgsCaller, RuntimeException {
...省略...
//參數準備,args數組中保存啓動SystemServer的啓動參數
String args[] = { //註釋1
"--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); //註釋2
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
//fork子進程,也是創建SystemServer進程
pid = Zygote.forkSystemServer( //註釋3
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
//運行在子進程中
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
//關閉zygote原有的socket
zygoteServer.closeServerSocket();
//處理SystemServer進程
handleSystemServerProcess(parsedArgs); //註釋4
}
return true;
}
註釋解析:
- 註釋1創建args數組,主要用來保存啓動SystemServer的啓動參數。
其中:
可以看出SystemServer進程的的用戶id和用戶組id都被設置爲了1000,並且擁有用戶組1001-1010、1018、1021、1032、3001-3010的權限。
進程名爲:system_server
啓動的類名爲:com.android.server.SystemServer
-
註釋2處將args數組封裝成Arguments對象,並給註釋3出的forkSystemServer函數調用
-
註釋3處調用Zygote的forkSystemServer方法,其內部會調用nativeForkSystemServer這個Native方法,nativeForkSystemServer會通過fork函數在當前進程創建一個子進程,即SystemServer進程。
-
註釋4處理SystemServer進程
2.4 runSelectLoop
在啓動SystemServer進程後,會執行ZygoteServer的runSelectLoop方法。
代碼路徑:frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
深入到runSelectLoop函數中:
void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
//sServerSocket是socket通信中的服務端,即zygote進程。保存到fds[0]
fds.add(mServerSocket.getFileDescriptor()); //註釋1
peers.add(null);
//無限循環等待AMS的請求
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) { //註釋2
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
//處理輪詢狀態,當pollFds有事件到來則往下執行,否則阻塞在這裏
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) { //註釋3
//採用I/O多路複用機制,當接收到客戶端發出連接請求或者數據處理請求時,則往下執行;
//否則進入continue,跳出本次循環
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
//即fds[0],代表的是sServerSocket,則意味着有客戶端連接請求;
//則創建ZygoteConnection對象,並添加到fds
ZygoteConnection newPeer = acceptCommandPeer(abiList); //註釋4
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
boolean done = peers.get(i).runOnce(this); //註釋5
if (done) {
peers.remove(i);
fds.remove(i);
}
}
}
}
}
註釋解析:
-
註釋1:處的mServerSocket就是在registerZygoteSocket函數中創建的服務端的Socket,調用getFileDescriptor()方法獲取該Socket的fd字段的值,並添加到fd列表fds中。
-
註釋2處通過遍歷將fds存儲的信息轉移到pollFds中
-
註釋3處對pollFds進行遍歷,如果i==0,說明服務端Socket與客戶端連接上了,即:當前Zygote進程與AMS建立了連接
-
註釋4處通過acceptCommandPeer方法得到ZygoteConnection類並添加到Socket連接列表peers中,然後將ZygoteConnection的fd添加到fd列表fds中,以便接收到AMS發送過來的請求
-
如果i不等於0,則說明AMS向Zygote進程發送了一個創建應用進程的請求,然後調用註釋5處ZygoteConnection的runOnce函數來創建一個新的應用程序進程,並在成功創建後,將這個連接從Socket連接列表peers和fds中移除。
3. 總結
3.1 Zygote啓動過程調用流程圖
3.2 Zygote進程啓動總結
Zygote進程啓動主要做了如下工作:
-
解析init.${ro.zygote}.rc中的參數,創建AppRuntime並調用它的start方法
-
調用AndroidRuntime的startVM()方法創建虛擬機,再調用startReg()註冊JNI函數
-
通過JNI調用ZygoteInit的main函數,進入Zygote的Java框架層
-
通過registerZygoteSocket方法建立Socket通道,zygote作爲通信的服務端,用於響應客戶端請求
-
preload()預加載通用類、drawable和color資源、openGL以及共享庫以及WebView,用於提高app啓動效率
-
啓動SystemServer進程
-
調用runSelectLoop(),隨時待命,當接收到請求創建新進程時,立即喚醒Zygote並執行相應工作