一、概述
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
283 bool zygote
= false;
284 bool startSystemServer
= false;
285 bool application
= false;
286 String8 niceName
;
287 String8 className
;
288
289 ++i
;
290 while (i
< argc
) {
291 const char* arg
= argv
[i
++];
292 if (strcmp(arg
, "--zygote") == 0) {
293 zygote
= true;
294 niceName
= ZYGOTE_NICE_NAME
;
295 } else if (strcmp(arg
, "--start-system-server") == 0) {
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
...
357 if (!niceName
.isEmpty()) {
358 runtime
.setArgv0(niceName
.string(), true );
359 }
360
361 if (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
1067 for (size_t i
= 0; i
< options
.size(); ++i
) {
1068 if (options
[i
] == startSystemServer
) {
1069
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
1086
1087
1088
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
1100 if (startReg(env
) < 0) {
1101 ALOGE("Unable to register all android natives\n");
1102 return;
1103 }
1104
1105
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
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
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
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
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
[]) {
ZygoteServer zygoteServer
= new ZygoteServer();
ZygoteHooks
.startZygoteNoThreadCreation();
...
try {
...
RuntimeInit
.enableDdms();
boolean startSystemServer
= false;
String socketName
= "zygote";
String abiList
= null
;
boolean enableLazyPreload
= false;
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.");
}
zygoteServer
.registerServerSocketFromEnv(socketName
);
if (!enableLazyPreload
) {
bootTimingsTraceLog
.traceBegin("ZygotePreload");
EventLog
.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START
,
SystemClock
.uptimeMillis());
preload(bootTimingsTraceLog
);
EventLog
.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END
,
SystemClock
.uptimeMillis());
bootTimingsTraceLog
.traceEnd();
} else {
Zygote
.resetNicePriority();
}
...
ZygoteHooks
.stopZygoteNoThreadCreation();
if (startSystemServer
) {
Runnable r
= forkSystemServer(abiList
, socketName
, zygoteServer
);
if (r
!= null
) {
r
.run();
return;
}
}
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列表,获取socket连接名称。(这里需要注意的是: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 {
String env
= System
.getenv(fullSocketName
);
fileDesc
= Integer
.parseInt(env
);
} catch (RuntimeException ex
) {
throw new RuntimeException(fullSocketName
+ " unset or invalid", ex
);
}
try {
FileDescriptor fd
= new FileDescriptor();
fd
.setInt$
(fileDesc
);
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();
128 bootTimingsTraceLog
.traceBegin("PreloadClasses");
129 preloadClasses();
130 bootTimingsTraceLog
.traceEnd();
131 bootTimingsTraceLog
.traceBegin("PreloadResources");
132 preloadResources();
133 bootTimingsTraceLog
.traceEnd();
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
143
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的方法中开启了禁止多线程的设置,完成后才关闭。