一、概述
zygote,在英語中是受精卵的意思。而在Android系統中也有這麼一個“受精卵進程” – Zygote進程。
在Android系統中,Zygote進程是所有Android進程的父進程。它通過fork的形式,創建SystemServer進程和應用程序進程。而Zygote進程則是通過linux系統的init進程啓動的。
在Android系統中各種進程的啓動過程:init進程 ––> Zygote進程 ––> SystemServer進程 ––>各種應用進程
其中,應用程序進程即我們編寫的應用的進程,SystemServer進程爲系統服務進程,比如後面還要學到的AMS、WMS都是在該進程中。
需要注意的是:
1、Android中所有的應用進程的創建都是一個應用進程通過Binder請求SystemServer進程,SystemServer進程發送socket消息給Zygote進程,統一由Zygote進程創建出來的。
2、Zygote進程在啓動的時候會創建一個虛擬機實例,因此通過Zygote進程在父進程,創建的子進程都會繼承這個虛擬機實例,App中的JAVA代碼可以得到翻譯執行。
3、進程與進程之間需要跨進程通信,由Zygote進程作爲父進程還可以獲得一個Binder線程池,這樣進程之間就可以使用Binder進行跨進程通信了。
二、啓動過程
/frameworks/base/cmds/app_process/app_main.cpp
192int main(int argc, char* const argv[])
193{
...
282 // Parse runtime arguments. Stop at first unrecognized option.
283 bool zygote = false;
284 bool startSystemServer = false;
285 bool application = false;
286 String8 niceName;
287 String8 className;
288
289 ++i; // Skip unused "parent dir" argument.
//init.rc中會配置一些參數,這裏進行比較設置一些變量走進不同的分支
290 while (i < argc) {
291 const char* arg = argv[i++];
292 if (strcmp(arg, "--zygote") == 0) {
//啓動的是Zygote進程
293 zygote = true;
294 niceName = ZYGOTE_NICE_NAME;
295 } else if (strcmp(arg, "--start-system-server") == 0) {
//啓動的是system-server進程
296 startSystemServer = true;
297 } else if (strcmp(arg, "--application") == 0) {
298 application = true;
299 } else if (strncmp(arg, "--nice-name=", 12) == 0) {
300 niceName.setTo(arg + 12);
301 } else if (strncmp(arg, "--", 2) != 0) {
302 className.setTo(arg);
303 break;
304 } else {
305 --i;
306 break;
307 }
308 }
309
...
//設置一個“好聽的名字” zygote,之前的名稱是app_process
357 if (!niceName.isEmpty()) {
358 runtime.setArgv0(niceName.string(), true /* setProcName */);
359 }
360
361 if (zygote) {
//通過runtime啓動zygote
364 runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
365 } else if (className) {
366 runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
367 } else {
368 fprintf(stderr, "Error: no class name or --zygote supplied.\n");
369 app_usage();
370 LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
371 }
372}
/frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
1057{
1058 ALOGD(">>>>>> START %s uid %d <<<<<<\n",
1059 className != NULL ? className : "(unknown)", getuid());
1060
1061 static const String8 startSystemServer("start-system-server");
1062
1063 /*
1064 * 'startSystemServer == true' means runtime is obsolete and not run from
1065 * init.rc anymore, so we print out the boot start event here.
1066 */
1067 for (size_t i = 0; i < options.size(); ++i) {
1068 if (options[i] == startSystemServer) {
1069 /* track our progress through the boot sequence */
1070 const int LOG_BOOT_PROGRESS_START = 3000;
1071 LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
1072 }
1073 }
1074
1075 const char* rootDir = getenv("ANDROID_ROOT");
1076 if (rootDir == NULL) {
1077 rootDir = "/system";
1078 if (!hasDir("/system")) {
1079 LOG_FATAL("No root directory specified, and /android does not exist.");
1080 return;
1081 }
1082 setenv("ANDROID_ROOT", rootDir, 1);
1083 }
1084
1085 //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
1086 //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
1087
1088 /* start the virtual machine */
1089 JniInvocation jni_invocation;
1090 jni_invocation.Init(NULL);
1091 JNIEnv* env;
1092 if (startVm(&mJavaVM, &env, zygote) != 0) {
1093 return;
1094 }
1095 onVmCreated(env);
1096
1097 /*
1098 * Register android functions.
1099 */
1100 if (startReg(env) < 0) {
1101 ALOGE("Unable to register all android natives\n");
1102 return;
1103 }
1104
1105 /*
1106 * We want to call main() with a String array with arguments in it.
1107 * At present we have two arguments, the class name and an option string.
1108 * Create an array to hold them.
1109 */
1110 jclass stringClass;
1111 jobjectArray strArray;
1112 jstring classNameStr;
1113
1114 stringClass = env->FindClass("java/lang/String");
1115 assert(stringClass != NULL);
1116 strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
1117 assert(strArray != NULL);
1118 classNameStr = env->NewStringUTF(className);
1119 assert(classNameStr != NULL);
1120 env->SetObjectArrayElement(strArray, 0, classNameStr);
1121
1122 for (size_t i = 0; i < options.size(); ++i) {
1123 jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
1124 assert(optionsStr != NULL);
1125 env->SetObjectArrayElement(strArray, i + 1, optionsStr);
1126 }
1127
1128 /*
1129 * Start VM. This thread becomes the main thread of the VM, and will
1130 * not return until the VM exits.
1131 */
1132 char* slashClassName = toSlashClassName(className != NULL ? className : "");
1133 jclass startClass = env->FindClass(slashClassName);
1134 if (startClass == NULL) {
1135 ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
1136 /* keep going */
1137 } else {
1138 jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
1139 "([Ljava/lang/String;)V");
1140 if (startMeth == NULL) {
1141 ALOGE("JavaVM unable to find main() in '%s'\n", className);
1142 /* keep going */
1143 } else {
1144 env->CallStaticVoidMethod(startClass, startMeth, strArray);
1145
1146#if 0
1147 if (env->ExceptionCheck())
1148 threadExitUncaughtException(env);
1149#endif
1150 }
1151 }
1152 free(slashClassName);
1153 //這行Log比較常見,因爲其他應用進程也是由zygote 進程fork 出來的,所有其他進程也包含這段代碼,如果其他進程在java 層crash,那麼也會走到這裏
1154 ALOGD("Shutting down VM\n");
1155 if (mJavaVM->DetachCurrentThread() != JNI_OK)
1156 ALOGW("Warning: unable to detach main thread\n");
1157 if (mJavaVM->DestroyJavaVM() != 0)
1158 ALOGW("Warning: VM did not shut down cleanly\n");
1159}
主要做了三件事情,1、調用startVm開啓虛擬機,2、調用startReg註冊JNI方法,3、使用JNI把Zygote進程啓動起來。啓動的類名爲 com.android.internal.os.ZygoteInit,方法名爲main。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
//1、創建ZygoteServer
ZygoteServer zygoteServer = new ZygoteServer();
//此處開啓設置,創建過程禁止多線程,爲什麼?後面會解答
ZygoteHooks.startZygoteNoThreadCreation();
...
try {
...
//設置DDMS可用
RuntimeInit.enableDdms();
//初始化啓動參數
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
// 2、解析app_main.cpp傳來的參數
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
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)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
if (abiList == null) {
throw new RuntimeException("No ABI list supplied.");
}
//3、創建一個Server端的Socket
zygoteServer.registerServerSocketFromEnv(socketName);
// 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());
//4、預加載進程的資源和類
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
}
...
//此處關閉設置,允許多線程
ZygoteHooks.stopZygoteNoThreadCreation();
//5、fork一個SystemServer進程
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
if (r != null) {
r.run();
return;
}
}
//6、啓動一個死循環,監聽socket,啓動新的應用進程
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
zygoteServer.closeServerSocket();
throw ex;
} finally {
zygoteServer.closeServerSocket();
}
if (caller != null) {
caller.run();
}
}
總結一下,在main方法中主要完成了6件事:
- 創建ZygoteServer
- 解析app_main.cpp傳來的參數,獲取abi列表,獲取scoket連接名稱。(這裏需要注意的是:android系統中進程之間通訊的方式是Binder,但是有一個例外是SystemService進程與Zygote進程之間是通過Socket的方式進行通訊的)
- 通過registerZygoteSocket函數,註冊Socket,作爲服務端,接受ActivityManagerService的請求來創建應用程序進程
- 預加載類和資源,包括顏色,R文件,drawable、類等
- 啓動system_server進程,SystemServer進程會啓動系統的關鍵服務
- 調用runSelectLoop函數監聽socket來等待客戶端請求
/frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
void registerServerSocketFromEnv(String socketName) {
if (mServerSocket == null) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
//從環境變量中獲取名爲ANDROID_SOCKET_zygote的fd
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}
try {
//創建一個FD對象
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
//不是使用IP和端口,這裏用這個FD創建LocalServerSocket
mServerSocket = new LocalServerSocket(fd);
mCloseSocketFd = true;
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
注意,這時通過fd創建了一個socket服務端–LocalServerSocket。當Zygote進程將SystemServer進程啓動後,就會在這個服務端的Socket上來等待ActivityManagerService請求Zygote進程來創建新的應用程序進程。
這裏爲什麼是使用FD創建呢?LocalServerSocket具體是怎麼創建的?
具體可以查看 -> https://www.jianshu.com/p/ab9b83a77af6
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
static void preload(TimingsTraceLog bootTimingsTraceLog) {
124 Log.d(TAG, "begin preload");
125 bootTimingsTraceLog.traceBegin("BeginIcuCachePinning");
126 beginIcuCachePinning();
127 bootTimingsTraceLog.traceEnd(); // BeginIcuCachePinning
128 bootTimingsTraceLog.traceBegin("PreloadClasses");
//預加載類,在preloadClasses方法中會通過Class.forName將類加載到系統中,生成字節碼
129 preloadClasses();
130 bootTimingsTraceLog.traceEnd(); // PreloadClasses
131 bootTimingsTraceLog.traceBegin("PreloadResources");
//預加載資源文件
132 preloadResources();
133 bootTimingsTraceLog.traceEnd(); // PreloadResources
134 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
135 nativePreloadAppProcessHALs();
136 Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
137 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");
138 preloadOpenGL();
139 Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
//預加載共享庫
140 preloadSharedLibraries();
//預加載文字資源
141 preloadTextResources();
142 // Ask the WebViewFactory to do any initialization that must run in the zygote process,
143 // for memory sharing purposes.
144 WebViewFactory.prepareWebViewInZygote();
145 endIcuCachePinning();
146 warmUpJcaProviders();
147 Log.d(TAG, "end preload");
148
149 sPreloadComplete = true;
150 }
從代碼中,我們可以看到哪些資源會被進行預加載:類文件、資源文件、共享庫、文字資源。總的來說,這些都是系統中App共享的資源。通過此時預加載,可以減少資源加載時間,加快了應用啓動速度。
在preloadClasses()函數中,會通過Class.forName將類加載到系統中,生成字節碼。此時預加載的類有哪些,可以查看清單:http://androidxref.com/8.0.0_r4/xref/frameworks/base/preloaded-classes
注意:這裏預加載資源都是在主線程中完成的,爲什麼不開多線程呢?猜測是防止多線程帶來的同步問題。所以纔在ZygoteInit的方法中開啓了禁止多線程的設置,完成後才關閉。