在上篇文章Android点击Launcher应用图标的应用程序启动过程(栈和进程的创建)中我们分析了在Home中点击应用图标后的启动过程及栈和进程的创建过程。我们讲到了AMS通过socket通信到了Zygote,那么下面我们继续看下Zygote是如何处理客户端请求的。
处理客户端请求
在ZygoteInit的main函数中通过zygoteServer.runSelectLoop(abiList)来接收客户端请求的:
Runnable runSelectLoop(String abiList) {
ArrayList fds = new ArrayList();
ArrayList peers = new ArrayList();
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
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;
}
...
if (i == 0) {//index==0表示selcet接收到的是Zygote的socket的事件
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
try {
ZygoteConnection connection = peers.get(i);
//调用ZygoteConnection对象的processOneCommand方法,ZygoteConnection是在index == 0时被添加到peers的
final Runnable command = connection.processOneCommand(this);
...
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(i);
fds.remove(i);
}
}
}
}...
}
}
每当有请求过来时,Zygote都会调用ZygoteConnection的processOneCommand()方法处理:
Runnable processOneCommand(ZygoteServer zygoteServer) {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
//读取客户端发送过来的参数
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
throw new IllegalStateException("IOException on command socket", ex);
}
...//省略一系列操作步骤
//fork一个新进程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
parsedArgs.instructionSet, parsedArgs.appDataDir);
try {
if (pid == 0) {//子进程
// in child
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.startChildZygote);
} else {//父进程
// In the parent. A pid < 0 indicates a failure and will be handled in
// handleParentProc.
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, descriptors, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
Zygote在处理客户端请求时会fork一个新的进程,接下来首先看一下handleChildProc()方法:
/Volumes/android/WORKING_DIRECTORY/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd, boolean isZygote) {
closeSocket();//关闭子进程,从Zygote fork过来的服务端socket
if (descriptors != null) {
try {
Os.dup2(descriptors[0], STDIN_FILENO);
Os.dup2(descriptors[1], STDOUT_FILENO);
Os.dup2(descriptors[2], STDERR_FILENO);
for (FileDescriptor fd: descriptors) {
IoUtils.closeQuietly(fd);
}
} catch (ErrnoException ex) {
Log.e(TAG, "Error reopening stdio", ex);
}
}
if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}
// End of the postFork event.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (parsedArgs.invokeWith != null) {//没有传入--invoke-with,所以这里走的是else
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.remainingArgs);
// Should not get here.
throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
} else {
if (!isZygote) { //如果是启动一个Zygite的子Zygote线程,这里为false所以走else
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
null /* classLoader */);
} else {
return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
}
这里调用ZygoteInit的zygoteInit()方法:
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
//指定系统log输出到andorid
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit();//初始化系统属性
ZygoteInit.nativeZygoteInit();
////应用初始化
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
这里注释已经说的很清楚了我们来看一下这几个方法的实现
- RuntimeInit.redirectLogStreams():
public static void redirectLogStreams() {
System.out.close();
System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));
System.err.close();
System.setErr(new AndroidPrintStream(Log.WARN, "System.err"));
}
这里将System.out 和 System.err 输出重定向到Android 的Log系统。
- RuntimeInit.commonInit():
protected static final void commonInit() {
if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
LoggingHandler loggingHandler = new LoggingHandler();
RuntimeHooks.setUncaughtExceptionPreHandler(loggingHandler);
Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));
RuntimeHooks.setTimeZoneIdSupplier(() -> SystemProperties.get("persist.sys.timezone"));
LogManager.getLogManager().reset();
new AndroidConfig();
String userAgent = getDefaultUserAgent();
System.setProperty("http.agent", userAgent);
NetworkManagementSocketTagger.install();
String trace = SystemProperties.get("ro.kernel.android.tracing");
if (trace.equals("1")) {
Slog.i(TAG, "NOTE: emulator trace profiling enabled");
Debug.enableEmulatorTraceOutput();
}
initialized = true;
}
初始化了一些系统属性,其中最重要的一点就是设置了一个未捕捉异常的handler,当代码有任何未知异常,就会执行它, 调试过Android代码的同学经常看到的"*** FATAL EXCEPTION IN SYSTEM PROCESS" 打印就出自这里的LoggingHandler对象。
- ZygoteInit.nativeZygoteInit():
该方法是一个本地方法, 最终会调用app_main的onZygoteInit函数 这里的作用是在新进程中引入Binder,也就说通过nativeZygoteInit以后,新的进程就可以使用Binder进程通信了。 - RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader):
protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {
// If the application calls System.exit(), terminate the process
// immediately without running any shutdown hooks. It is not possible to
// shutdown an Android application gracefully. Among other things, the
// Android runtime shutdown hooks close the Binder driver, which can cause
// leftover running threads to crash before the process actually exits.
nativeSetExitWithoutCleanup(true);
// We want to be fairly aggressive about heap utilization, to avoid
// holding on to a lot of memory that isn't needed.
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
final Arguments args = new Arguments(argv);
// The end of of the RuntimeInit event (see #zygoteInit).
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// Remaining arguments are passed to the start class's static main
return findStaticMain(args.startClass, args.startArgs, classLoader);
}
在applicationInit()的最后,会通过调用findStaticMain来调用args.startClass这个类的main()方法。在前面介绍socket的客户端代码时,在startProcessLocked()中传入的这个类为"android.app.ActivityThread"。所以接下来findStaticMain()的功能相信大家都已经知道了,就是调用ActivityThread类的main(),下面是代码:
protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader) {
Class> cl;
try {
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"Missing static main on " + className, ex);
} catch (SecurityException ex) {
throw new RuntimeException(
"Problem getting static main on " + className, ex);
}
int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException(
"Main method is not public and static on " + className);
}
/*
* This throw gets caught in ZygoteInit.main(), which responds
* by invoking the exception's run() method. This arrangement
* clears up all the stack frames that were required in setting
* up the process.
*/
return new MethodAndArgsCaller(m, argv);
}
这个方法本身功能就是调用ActivityThread类的main(),没什么可说的。这里痛class获取ActivityThreadActivityThread类的main()方法封装在new MethodAndArgsCaller中并返回到ZygoteInit.main()中(老的版本统统一个奇怪的方式:抛出ZygoteInit.MethodAndArgsCaller异常会在ZygoteInit.main()中被捕获处理):
public static void main(String argv[]) {
...
// We're in the child process and have exited the select loop. Proceed to execute the
// command.
if (caller != null) {
caller.run();
}
}
这里的caller是com.android.internal.os.RuntimeInit.MethodAndArgsCaller,它实现了Runnable接口,这里调用器run方法。这里需要注意的是:cller.run在子进程(即新的进程,不是Zygote进程)中的动作。还记得前面介绍的processOneCommand()方法吗?我们在processOneCommand中创建了一个新的进程。如果读者还有不明白这里为什么是在子进程,可以自行学习Linux fork()的原理。那么我们继续看下它的run方法里做了什么:
public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
Throwable cause = ex.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException(ex);
}
}
这里 看到了mMethod.invoke(null, new Object[] { mArgs }),原来最后还是会调用invoke方法通过反射的方式调用ActivityThread的main方法。
到了这里,相信大家都会有一个疑问:既然最后还是通过invoke来反射调用main方法,那绕这一大圈子到底在折腾什么?
有疑问的读者,有没有去思考过另外一个问题:我们为什么要通过Zygote去创建进程,而不是直接创建一个新的进程出来呢?这就要从Zygote创建进程的机制来解释。相信我们还记得在ZygoteInit的main函数中我们通过preload来预加载类和资源。所以这些被预加载的类和资源都存在于Zygote进程中。在通过Zygote创建进程时,我们是通过fork来创建的。 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同,相当于克隆了一个自己。所以,Zygote通过fork的方式创建新的应用进程的同时,会将对系统的(主要是framework中的)一些类和资源的引用同时复制给子进程,这样子进程中就可以使用这些资源了。这也是为什么所有的应用程序可以共享Framework中的类和资源的原因。
好了到这里就已经创建好新的应用进程了,接下来就是应用的初始化过程了,下篇文章再见了!