上一篇文章咱们分析了init进程的启动过程,启动过程当中主要作了三件事,其中一件就是建立了Zygote进程,那么Zygote进程是什么,它作了哪些事呢?java
在Android系统中,DVM(Dalvik虚拟机)、应用程序进程以及运行系统的关键服务的SystemServer进程都是由Zygote进程来建立的,咱们也将它称为孵化器。它经过fork (复制进程)的形式来建立应用程序进程和SystemServer进程,因为Zygote进程在启动时会建立DVM,所以经过fork而建立的应用程序进程和SystemServer进程能够在内部获取一个DVM的实例拷贝。android
咱们从上篇文章得知init启动zygote时主要是调用app_main.cpp的main函数中的AppRuntime的start来启动zygote进程的,咱们就从app_main.cpp的main函数开始分析,以下所示。bash
int main(int argc, char* const argv[])
{
...
while (i < argc) {
const char* arg = argv[i++];
// 1
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
// 2
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
// 3
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;
}
}
...
// 4
if (zygote) {
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.");
}
}
复制代码
由前可知,Zygote进程都是经过fork自身来建立子进程的,这样Zygote进程和由它fork出来的子进程都会进入app_main.cpp的main函数中,因此在mian函数中,首先会判断当前运行在哪一个进程,在注释1处,会判断参数arg中释放包含了”–zygote”,若是包含了,则说明main函数是运行在Zygote进程中的并会将zygote标记置为true。在注释2处会判断参数arg中是否包含了”–start-system-server”,若是包含了则表示当前是处在SystemServer进程中并将startSystemServer设置为true。同理在注释3处会判断参数arg是否包含”–application”,若是包含了说明当前处在应用程序进程中并将application标记置为true。最后在注释4处,当zygote标志是true的时候,也就是当前正处在Zygote进程中时,则使用AppRuntime.start()函数启动Zygote进程。服务器
咱们接着看看AndroidRuntime的start函数:app
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
...
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
// 1
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
/*
* 二、Register android functions.
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
...
// 3
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);
}
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
// 4
char* slashClassName = toSlashClassName(className != NULL ? className : "");
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
// 6
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 {
// 6
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);
...
}
复制代码
首先,在AndroidRuntime的start函数中,会如今注释1处使用startVm函数来启动弄Java虚拟机,而后在注释2处使用startReg函数为Java虚拟机注册JNI方法。在注释3处的classNameStr是传入的参数,值为com.android.internall.os.ZygoteInit。而后在注释4处使用toSlashClassName函数将className的”.”替换为”/“,替换后的值为com/android/internal/os/ZygoteInit。接着根据这个值找到ZygoteInit并在注释5处找到ZygoteInit的main函数,最后在注释6处使用JNI调用ZygoteInit的main函数,之因此这里要使用JNI,是由于ZygoteInit是java代码。最终,Zygote就从Native层进入了Java FrameWork层。在此以前,并无任何代码进入Java FrameWork层面,所以能够认为,Zygote开创了java FrameWork层。socket
接着,咱们看看Zygoteinit.java中的main方法:ide
public static void main(String argv[]) {
...
try {
...
// 1
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());
// 2
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
}
...
if (startSystemServer) {
// 3
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;
}
}
Log.i(TAG, "Accepting command socket connections");
// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
// 4
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
zygoteServer.closeServerSocket();
}
// We're in the child process and have exited the select loop. Proceed to execute the // command. if (caller != null) { caller.run(); } } 复制代码
首先,在注释1处调用了ZygoteServer的registerServerSocketFromEnv方法建立了一个名为”zygote”的Server端的Socket,它用来等待ActivityManagerService请求Zygote来建立新的应用程序进程。我首先分析下registerServerSocketFromEnv方法的处理逻辑,源码以下所示:函数
private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
void registerServerSocketFromEnv(String socketName) {
if (mServerSocket == null) {
int fileDesc;
// 1
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
// 2
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);
// 3
mServerSocket = new LocalServerSocket(fd);
mCloseSocketFd = true;
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
复制代码
首先,会在注释1处将Socket的名字拼接为“ANDROID_SOCKET_zygote“,在注释2处调用System.getenv()方法获得该Socket对应的环境变量中的值,而后将这个Socket环境变量值解析为int类型的文件描述符参数。接着,在注释4处,使用上面获得的文件描述符参数获得一个文件描述符,并由此新建一个服务端Socket。当Zygote进程将SystemServer进程启动红藕,就会在这个服务端Socket上等待AMS请求Zygote进程去建立新的应用程序进程。oop
接着,咱们回到ZygoteInit的main方法,在注释2处会预加载类和资源。而后在注释3处,使用了forkSystemServer()方法去建立SystemServer进程。forkSystemServer()方法核心代码以下所示:post
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
// 一系统建立SystemServer进程所需参数的准备工做
try {
...
/* Request to fork the system server process */
// 3.1
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.runtimeFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket();
// 3.2
return handleSystemServerProcess(parsedArgs);
}
return null;
}
复制代码
能够看到,forkSystemServer()方法中,注释3.1调用了Zygote的forkSystemServer()方法去建立SystemServer进程,其内部会执行nativeForkSystemServer这个Native方法,它最终会使用fork函数在当前进程建立一个SystemServer进程。若是pid等于0,即当前是处于新建立的子进程ServerServer进程中,则在注释3.2处使用handleSystemServerProcess()方法处理SystemServer进程的一些处理工做。
咱们再回到Zygoteinit.java中main方法中的注释4处,这里调用了ZygoteServer的runSelectLoop方法来等等ActivityManagerService来请求建立新的应用程序进程,runSelectLoop()方法以下所示:
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
// 1
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
// 二、无限循环等待AMS请求建立应用程序进程
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);
}
// 3
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
// 4
if (i == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
try {
ZygoteConnection connection = peers.get(i);
// 5
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) {
if (!mIsForkChild) {
// We're in the server so any exception here is one that has taken place // pre-fork while processing commands or reading / writing from the // control socket. Make a loud noise about any such exceptions so that // we know exactly what failed and why. Slog.e(TAG, "Exception executing zygote command: ", e); // Make sure the socket is closed so that the other end knows immediately // that something has gone wrong and doesn't time out waiting for a
// response.
ZygoteConnection conn = peers.remove(i);
conn.closeSocket();
fds.remove(i);
} else {
// We're in the child so any exception caught here has happened post // fork and before we execute ActivityThread.main (or any other main() // method). Log the details of the exception and bring down the process. Log.e(TAG, "Caught post-fork exception in child process.", e); throw e; } } finally { // Reset the child flag, in the event that the child process is a child- // zygote. The flag will not be consulted this loop pass after the Runnable // is returned. mIsForkChild = false; } } } } } 复制代码
首先,在注释1处,会调用服务端的mServerSocket的getFileDescriptor()函数来去得到自身的fd字段值并加入fds列表中。而后,在注释2处,无限循环用来等待AMS请求Zygote进程建立新的应用程序进程。在注释3处会遍历pollFds这个fd列表,若是i等于0,则说明服务端Socket与客户端链接上了,即当前Zygote进程与AMS进程创建了链接。接着,在注释4处调用acceptCommandPeer()方法获得ZygoteConnection对象,并将其加入peers列表中。若是i不等于0,则代表AMS想Zygote进程发送了一个建立应用程序进程的请求,最后会在注释5处执行ZygoteConnection.runOnce方法去建立一个新的应用程序进程。
从以上的分析能够得知,Zygote进程启动中承担的主要职责以下: