标签:zygote 孵化器 进程启动 zygote请求响应过程 android进程创建
在Zygote的诞生一文中init进程是如何一步步创建Zygote进程的,也了解了Zygote的进程的作用。Zygote进程的诞生对于整个Java世界可以说有着”开天辟地“的作用,它创建了Java虚拟机,并且繁殖了Java世界的核心服务system_server进程,在完成Java世界的初创工作以后,Zygote并没有死去,它只是暂时的沉睡(socket事件堵塞)在那里,一旦有需要(有客户端请求的到来),它便马上起来工作。本文接下来就将分析一下Zygote是如何监听和处理socket事件的。
首先让我们一起来回忆一下Zygote的main方法:
@frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
try {
registerZygoteSocket();//注册zygote用的socket
......
runSelectLoop();//变成守护进程,接收socket信息进行处理
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
main()方法首先在registerZygoteSocket中注册了Zygote的 服务端Socket对象,然后在完成一系列初创工作后调用runSelectLoop进入到死循环中,等待客户端事件的到来。到了这里我们不禁会问,Zygote进程作为服务端,那客户端是谁呢?Zygote接收到客户端连接以后又是如何处理的呢?下面我们就带着这两个问题一起来分析。
@/frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
......
try {
......
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, null);
.......
}
@/frameworks/base/core/java/android/os/Process.java
/**
* Start a new process.
*
* <p>If processes are enabled, a new process is created and the
* static main() function of a <var>processClass</var> is executed there.
* The process will continue running after this function returns.
*
* <p>If processes are not enabled, a new thread in the caller‘s
* process is created and main() of <var>processClass</var> called there.
*
* <p>The niceName parameter, if not an empty string, is a custom name to
* give to the process instead of using processClass. This allows you to
* make easily identifyable processes even if you are using the same base
* <var>processClass</var> to start them.
*
* @param processClass The class to use as the process‘s main entry
* point.
* @param niceName A more readable name to use for the process.
* @param uid The user-id under which the process will run.
* @param gid The group-id under which the process will run.
* @param gids Additional group-ids associated with the process.
* @param debugFlags Additional flags.
* @param targetSdkVersion The target SDK version for the app.
* @param seInfo null-ok SE Android information for the new process.
* @param zygoteArgs Additional arguments to supply to the zygote process.
*
* @return An object that describes the result of the attempt to start the process.
* @throws RuntimeException on fatal start failure
*
* {@hide}
*/
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}startViaZygote()方法的实现如下:
/**
* Starts a new process via the zygote mechanism.
*
* @param processClass Class name whose static main() to run
* @param niceName ‘nice‘ process name to appear in ps
* @param uid a POSIX uid that the new process should setuid() to
* @param gid a POSIX gid that the new process shuold setgid() to
* @param gids null-ok; a list of supplementary group IDs that the
* new process should setgroup() to.
* @param debugFlags Additional flags.
* @param targetSdkVersion The target SDK version for the app.
* @param seInfo null-ok SE Android information for the new process.
* @param extraArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
* @throws ZygoteStartFailedEx if process start failed for any reason
*/
private static ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
ArrayList<String> argsForZygote = new ArrayList<String>();
// --runtime-init, --setuid=, --setgid=,
// and --setgroups= must go first
argsForZygote.add("--runtime-init");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {
argsForZygote.add("--enable-jni-logging");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {
argsForZygote.add("--enable-safemode");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {
argsForZygote.add("--enable-debugger");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
argsForZygote.add("--enable-checkjni");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
argsForZygote.add("--enable-assert");
}
if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER) {
argsForZygote.add("--mount-external-multiuser");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL) {
argsForZygote.add("--mount-external-multiuser-all");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
//TODO optionally enable debuger
//argsForZygote.add("--enable-debugger");
// --setgroups is a comma-separated list
if (gids != null && gids.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--setgroups=");
int sz = gids.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(‘,‘);
}
sb.append(gids[i]);
}
argsForZygote.add(sb.toString());
}
if (niceName != null) {
argsForZygote.add("--nice-name=" + niceName);
}
if (seInfo != null) {
argsForZygote.add("--seinfo=" + seInfo);
}
argsForZygote.add(processClass);
if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}
return zygoteSendArgsAndGetResult(argsForZygote);
}
}startViaZygote的绝大部分代码都在处理传递到Zygote中的参数,与Zygote通信通过zygoteSendArgsAndGetResult()方法完成:
/**
* Sends an argument list to the zygote process, which starts a new child
* and returns the child‘s pid. Please note: the present implementation
* replaces newlines in the argument list with spaces.
* @param args argument list
* @return An object that describes the result of the attempt to start the process.
* @throws ZygoteStartFailedEx if process start failed for any reason
*/
private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args)
throws ZygoteStartFailedEx {
openZygoteSocketIfNeeded();//确保和Zygote通信的socket已被打开
try {
/**
* See com.android.internal.os.ZygoteInit.readArgumentList()
* Presently the wire format to the zygote process is:
* a) a count of arguments (argc, in essence)
* b) a number of newline-separated argument strings equal to count
*
* After the zygote process reads these it will write the pid of
* the child or -1 on failure, followed by boolean to
* indicate whether a wrapper process was used.
*/
sZygoteWriter.write(Integer.toString(args.size()));
sZygoteWriter.newLine();
int sz = args.size();
for (int i = 0; i < sz; i++) {//发送请求参数到Zygote
String arg = args.get(i);
if (arg.indexOf(‘\n‘) >= 0) {
throw new ZygoteStartFailedEx(
"embedded newlines not allowed");
}
sZygoteWriter.write(arg);
sZygoteWriter.newLine();
}
sZygoteWriter.flush();
// Should there be a timeout on this?
ProcessStartResult result = new ProcessStartResult();
result.pid = sZygoteInputStream.readInt();//Zygote处理完成会返回子进程的pid(即要创建的进程)
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
result.usingWrapper = sZygoteInputStream.readBoolean();
return result;
} catch (IOException ex) {
try {
if (sZygoteSocket != null) {
sZygoteSocket.close();
}
} catch (IOException ex2) {
// we‘re going to fail anyway
Log.e(LOG_TAG,"I/O exception on routine close", ex2);
}
sZygoteSocket = null;
throw new ZygoteStartFailedEx(ex);
}
}到这里位置,客户端请求Zygote创建进程的请求就发送出去了,Zygote会返回进行的pid给客户端(ActivityMangerService)。由于ActivityMangerService在SystemServer进程中,所以这里即SystemServer进程通过socket向Zygote发送了信息。
接下来,我们看一下看一下Zygote是如何处理客户端请求的。
/**
* Runs the zygote process‘s select loop. Accepts new connections as
* they happen, and reads commands from connections one spawn-request‘s
* worth at a time.
*
* @throws MethodAndArgsCaller in a child process when a main() should
* be executed.
*/
private static void runSelectLoop() throws MethodAndArgsCaller {
......
while (true) {//死循环
......
if (index < 0) {
throw new RuntimeException("Error in select()");
} else if (index == 0) {//index==0表示selcet接收到的是Zygote的socket的事件
ZygoteConnection newPeer = acceptCommandPeer();
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {//调用ZygoteConnection对象的runOnce方法,ZygoteConnection是在index == 0时被添加到peers的
boolean done;
done = peers.get(index).runOnce();
if (done) {
peers.remove(index);
fds.remove(index);
}
}
}
}
每当有请求过来时,Zygote都会调用ZygoteConnection的runOnce()方法处理:
@/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
/**
* Reads one start command from the command socket. If successful,
* a child is forked and a {@link ZygoteInit.MethodAndArgsCaller}
* exception is thrown in that child while in the parent process,
* the method returns normally. On failure, the child is not
* spawned and messages are printed to the log and stderr. Returns
* a boolean status value indicating whether an end-of-file on the command
* socket has been encountered.
*
* @return false if command socket should continue to be read from, or
* true if an end-of-file has been encountered.
* @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main()
* method in child process
*/
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
args = readArgumentList();//读取客户端发送过来的参数
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
Log.w(TAG, "IOException on command socket " + ex.getMessage());
closeSocket();
return true;
}
if (args == null) {
// EOF reached.
closeSocket();
return true;
}
/** the stderr of the most recent request, if avail */
PrintStream newStderr = null;
if (descriptors != null && descriptors.length >= 3) {
newStderr = new PrintStream(
new FileOutputStream(descriptors[2]));
}
int pid = -1;
FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null;
try {
parsedArgs = new Arguments(args);
applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyCapabilitiesSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyDebuggerSystemProperty(parsedArgs);
applyInvokeWithSystemProperty(parsedArgs);
int[][] rlimits = null;
if (parsedArgs.rlimits != null) {
rlimits = parsedArgs.rlimits.toArray(intArray2d);
}
if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) {
FileDescriptor[] pipeFds = Libcore.os.pipe();
childPipeFd = pipeFds[1];
serverPipeFd = pipeFds[0];
ZygoteInit.setCloseOnExec(serverPipeFd, true);
}
//fork一个新进程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName);
} catch (IOException ex) {
logAndPrintError(newStderr, "Exception creating pipe", ex);
} catch (ErrnoException ex) {
logAndPrintError(newStderr, "Exception creating pipe", ex);
} catch (IllegalArgumentException ex) {
logAndPrintError(newStderr, "Invalid zygote arguments", ex);
} catch (ZygoteSecurityException ex) {
logAndPrintError(newStderr,
"Zygote security policy prevents request: ", ex);
}
try {
if (pid == 0) {//子进程
// in child
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
// should never get here, the child is expected to either
// throw ZygoteInit.MethodAndArgsCaller or exec().
return true;
} else {//父进程
// in parent...pid of < 0 means failure
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}Zygote在处理客户端请求时会fork一个新的进程,接下来进一步分析一下在子进程和父进程中都做了些什么Zygote进程【2】——Zygote的分裂,码迷,mamicode.com
标签:zygote 孵化器 进程启动 zygote请求响应过程 android进程创建
原文地址:http://blog.csdn.net/zhgxhuaa/article/details/24584807