上一篇文章咱們分析了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進程啓動中承擔的主要職責以下: