Android -- ActivityManagerService为应用创建进程流程简析
之前分析了Activity的启动过程,得知当系统发现当前Activity的宿主进程还不存在时,则会想先去为它创建一个进程,然后再去启动该Activity。这篇博文主要就介绍AMS为应用创建进程的过程,用来填充上一篇文章中不足的部分。
AMS在发现要启动的Activity所要处于的进程不存在时,就会去创建进程;这部分处理是调用AMS::startProcessLocked()函数实现的:
void ActivityStackSupervisor::startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
r.task.stack.setLaunchTime(r);
if (app != null && app.thread != null) {
try {
if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
// Don't add this if it is a platform component that is marked
// to run in multiple processes, because this is actually
// part of the framework so doesn't make sense to track as a
// separate apk in the process.
app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
mService.mProcessStats);
}
realStartActivityLocked(r, app, andResume, checkConfig);//如果应用进程已经启动了,则调用该函数继续处理;其会触发类的onCreate()方法
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);//应用进程没有启动,则去启动应用进程
}
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead/*true*/, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting/*false*/,
boolean isolated/*false*/, boolean keepIfLarge/*true*/) {
return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
null /* crashHandler */);//为应用组件创建新进程
}
final ProcessRecord AMS::startProcessLocked(String processName, ApplicationInfo info,
boolean knownToBeDead/*true*/, int intentFlags, String hostingType, ComponentName hostingName,
boolean allowWhileBooting/*false*/, boolean isolated/*false*/, int isolatedUid, boolean keepIfLarge/*true*/,
String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
long startTime = SystemClock.elapsedRealtime();
ProcessRecord app;
if (!isolated) {//isolated表示是否可以运行已存在的同名进程程中
app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
...
} else {
// If this is an isolated process, it can't re-use an existing process.
app = null;
}
...
String hostingNameStr = hostingName != null
? hostingName.flattenToShortString() : null;
if (app == null) {//因为应用进程没有启动,所以这里app为null
checkTime(startTime, "startProcess: creating new process record");
app = newProcessRecordLocked(info, processName, isolated, isolatedUid);//创建ProcessRecord对象,并保存在AMS::mProcessNames列表中
if (app == null) {
Slog.w(TAG, "Failed making new process record for "
+ processName + "/" + info.uid + " isolated=" + isolated);
return null;
}
app.crashHandler = crashHandler;
checkTime(startTime, "startProcess: done creating new process record");
} else {
...
}
...
startProcessLocked(
app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);//调用startProcessLocked()创建进程
checkTime(startTime, "startProcess: done starting proc!");
return (app.pid != 0) ? app : null;
}
ProcessRecord在AMS中代表一个进程,它维护了进程的一些信息。
在上一篇文章分析的场景中,我们点击运行的应用是第一次运行,则代码中的app为null,此时会调用startProcessLocked()函数去处理进程创建动作;
private final void AMS::startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
long startTime = SystemClock.elapsedRealtime();
if (app.pid > 0 && app.pid != MY_PID) {
checkTime(startTime, "startProcess: removing from pids map");
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.remove(app.pid);//把进程id先移除,防止重复
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);//移除存在的PROC_START_TIMEOUT_MSG message,它会用来计算进程启动时间
}
checkTime(startTime, "startProcess: done removing from pids map");
app.setPid(0);
}
...
try {
...
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
boolean isActivityProcess = (entryPoint == null);
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);//创建应用进程,并返回进程号;其中指定了该进程的入口函数为android.app.ActivityThread::main()
...
synchronized (mPidsSelfLocked) {//发送PROC_START_TIMEOUT_MSG消息,如果指定时间截止,应用还未启动成功,则会报ANR
this.mPidsSelfLocked.put(startResult.pid, app);//将创建的应用进程的进程号和ProcessRecord实例保存起来
if (isActivityProcess) {
Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, startResult.usingWrapper
? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}
}
checkTime(startTime, "startProcess: done updating pids map");
} catch (RuntimeException e) {
...
}
}
首先会判断当前需要创建的进程是否是应用进程。如果是,则会指定该进程的入口函数为ActivityThread::main(),接着根据参数调用Process::start()函数去创建进程,随后会发送一个进程创建超时的消息,处理进程创建超时异常。
Process::start()的实现如下:
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 abi,
String instructionSet,
String appDataDir,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
...
}
}
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 abi,
String instructionSet,
String appDataDir,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
ArrayList<String> argsForZygote = new ArrayList<String>();
// --runtime-args, --setuid=, --setgid=,
// and --setgroups= must go first
argsForZygote.add("--runtime-args");////表示剩余的arg列表应该传递给com.android.internal.os.RuntimeInit,而不是直接处理
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
...
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi)/*与Zygote进程的zygote socket建立连接,得到输入/输出流*/, argsForZygote);//调用zygoteSendArgsAndGetResult();通过建立的与Zygote进程之间的socket,向Zygote发送创建新进程的请求
}
}
从代码可以,调用Process::zygoteSendArgsAndGetResult()之前,会先调用Process::openZygoteSocketIfNeeded()函数建立与Zygote父进程间通信的socket通道。
我们知道,Linux中子进程的创建采用复制的形式;系统在创建Zygote进程时,会根据init.rc中的配置为它创建一个名为"zygote"的socket,并以键值对的形式:以socket的名字为键,它对应的文件描述符为值发布到系统中。并且,Zygote进程初始化过程中会进入一个无限循环,并在此套接字上监听、接收来自AMS为应用创建子进程的请求。
基于此,我们就能知道AMS为了向Zygote父进程发送创建进程请求,就必须连接到"zygote"套接字上,并通过它向Zygote进程发送创建进程需要的数据。
了解这些之后,我们先分析Process::openZygoteSocketIfNeeded()函数的实现:
* Tries to open socket to Zygote process if not already open. If
* already open, does nothing. May block and retry.
*/
private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {//如果当前的LocalSocket没有创建或者已经被关闭,则重新创建连接到"zygote"的LocalSocket
try {
primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);//向Zygote进程的"zygote" Server端socket建立一个连接;并保存到Process.primaryZygoteState成员变量中
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
}
if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}
// The primary zygote didn't match. Try the secondary.
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
try {
secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
}
}
if (secondaryZygoteState.matches(abi)) {
return secondaryZygoteState;
}
throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}
ZygoteState可以看做是一个工具类,它内部会创建一个LocalSocket去连接"zygote"这个socket,并获取这个连接的输入/输出流保存到内部;这样,就可以通过保存的输入/输出流与"zygote"进行数据交互了
ZygoteState::connect()函数实现:
public static class ZygoteState {
final LocalSocket socket;
final DataInputStream inputStream;
final BufferedWriter writer;
...
public static ZygoteState ZygoteState::connect(String socketAddress) throws IOException {
DataInputStream zygoteInputStream = null;
BufferedWriter zygoteWriter = null;
final LocalSocket zygoteSocket = new LocalSocket();
try {
zygoteSocket.connect(new LocalSocketAddress(socketAddress,
LocalSocketAddress.Namespace.RESERVED));
zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
zygoteWriter = new BufferedWriter(new OutputStreamWriter(
zygoteSocket.getOutputStream()), 256);
} catch (IOException ex) {
try {
zygoteSocket.close();
} catch (IOException ignore) {
}
throw ex;
}
String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
Log.i("Zygote", "Process: zygote socket opened, supported ABIS: " + abiListString);
return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
Arrays.asList(abiListString.split(",")));
}
}
再看转回去看:
/**
* 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.
*
* @throws ZygoteStartFailedEx if process start failed for any reason
*/
private static ProcessStartResult Process::zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
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.
*/
final BufferedWriter writer = zygoteState.writer;
final DataInputStream inputStream = zygoteState.inputStream;
writer.write(Integer.toString(args.size()));
writer.newLine();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
writer.write(arg);//将数据发送到Zygote进程端,用于创建应用子进程
writer.newLine();
}
writer.flush();
// Should there be a timeout on this?
ProcessStartResult result = new ProcessStartResult();
// Always read the entire result from the input stream to avoid leaving
// bytes in the stream for future process starts to accidentally stumble
// upon.
result.pid = inputStream.readInt();//获取Zygote进程,即这次通信中的Server端返回的创建的子进程的pid
result.usingWrapper = inputStream.readBoolean();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
return result;
} catch (IOException ex) {
zygoteState.close();
throw new ZygoteStartFailedEx(ex);
}
}
将创建进程所需的参数通过连接到"zygote"的输出流写入,传给Zygote进程用于创建应用子进程;然后,会从输入流得到创建子进程的pid信息,返回给调用者。
我们已经知道,Zygote进程启动的末尾,会进入一个循环,不断等待处理AMS发出的创建应用子进程的请求,这部分是在ZygoteInit中处理的:
/**
* 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 ZygoteInit::runSelectLoop(String abiList) throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
fds.add(sServerSocket.getFileDescriptor());//将sServerSocket(zygote)代表的socket的文件描述符加入到fds集合中,进行监听
peers.add(null);
while (true) {//采用无线循环的方式来监听来自AMS的创建新应用进程的请求
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);//监听pollFds中的那些socket是否有数据可读
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {//如果i = 0,则说明某个服务已经通过zygote这个socket与Zygote这个进程创建了socket连接;注意,此时仅仅是创立连接(LocalSocket::connect());还未发送数据.AMS也是如此
ZygoteConnection newPeer = acceptCommandPeer(abiList);//ZygoteConnection对象表示每一个通过"zygote"与Zygote进程建立的连接
peers.add(newPeer);//将这次的连接保存到peers中
fds.add(newPeer.getFileDesciptor());//将该次创建连接的描述符加入到fds数组中,进行数据监听
} else {
boolean done = peers.get(i).runOnce();//此时,代表有数据发送过来;调用ZygoteConnection::runOnce()处理创建应用进程的请求
if (done) {//该次请求完成后,就移除这次的连接和对应的LocalSocket的文件描述符
peers.remove(i);
fds.remove(i);
}
}
}
}
}
如果AMS作为Client端,连接到"zygote" Server端时,就会创建一个ZygoteConnection对象来描述这次连接:
/**
* Waits for and accepts a single command connection. Throws
* RuntimeException on failure.
*/
private static ZygoteConnection ZygoteInit::acceptCommandPeer(String abiList) {
try {
return new ZygoteConnection(sServerSocket.accept(), abiList);
} catch (IOException ex) {
throw new RuntimeException(
"IOException during accept()", ex);
}
}
mServerSocket就是Zygote进程中的"zygote" socket,它接收请求后,会得到Client端的套接字信息,并保存到当次ZygoteConnection对象中:
/**
* A connection that can make spawn requests.
*/
class ZygoteConnection {
private static final String TAG = "Zygote";
/**
* {@link android.net.LocalSocket#setSoTimeout} value for connections.
* Effectively, the amount of time a requestor has between the start of
* the request and the completed request. The select-loop mode Zygote
* doesn't have the logic to return to the select loop in the middle of
* a request, so we need to time out here to avoid being denial-of-serviced.
*/
private static final int CONNECTION_TIMEOUT_MILLIS = 1000;
/** max number of arguments that a connection can specify */
private static final int MAX_ZYGOTE_ARGC = 1024;
/**
* The command socket.
*
* mSocket is retained in the child process in "peer wait" mode, so
* that it closes when the child process terminates. In other cases,
* it is closed in the peer.
*/
private final LocalSocket mSocket;
private final DataOutputStream mSocketOutStream;
private final BufferedReader mSocketReader;
private final Credentials peer;
private final String abiList;
/**
* Constructs instance from connected socket.
*
* @param socket non-null; connected socket
* @param abiList non-null; a list of ABIs this zygote supports.
* @throws IOException
*/
ZygoteConnection(LocalSocket socket, String abiList) throws IOException {
mSocket = socket;
this.abiList = abiList;
mSocketOutStream
= new DataOutputStream(socket.getOutputStream());
mSocketReader = new BufferedReader(
new InputStreamReader(socket.getInputStream()), 256);
mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);
try {
peer = mSocket.getPeerCredentials();
} catch (IOException ex) {
Log.e(TAG, "Cannot read peer credentials", ex);
throw ex;
}
}
}
其中成员mSocketOutStream/mSocketReader可以用于Server、Client端交互数据,比如:使用mSocketOutStream,在Zygote进程中将创建的子进程的pid信息返回给AMS。Zygote进程内部收到AMS发送过来的创建应用子进程的请求及数据后,会由ZygoteConnection类处理:
/**
* 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) {//参数读取失败时,会关掉当次socket连接
// 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);//将读到的参数保存到Arguments对象中
...
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
parsedArgs.appDataDir);//调用forkAndSpecialize()函数创建新进程
} 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) {//pid = 0,表示在新创建的子进程中
// in child
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);//调用handleChildProc()来启动子进程
// 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);
}
}
该函数会抛出一个ZygoteInit.MethodAndArgsCaller类型的异常,这是我们需要注意的;在子进程创建完毕,要进入它的入口函数时,会通过该异常的捕获来清空子进程的调用堆栈,同时出发进入ActivityThread::main()的操作。
首先读出AMS创建子进程传过来的参数并保存起来,然后通过调用接口,进入JNI由fork()函数来真正创建子进程:
/**
* Forks a new VM instance. The current VM must have been started
* with the -Xzygote flag. <b>NOTE: new instance keeps all
* root capabilities. The new process is expected to call capset()</b>.
*
* @param uid the UNIX uid that the new process should setuid() to after
* fork()ing and and before spawning any threads.
* @param gid the UNIX gid that the new process should setgid() to after
* fork()ing and and before spawning any threads.
* @param gids null-ok; a list of UNIX gids that the new process should
* setgroups() to after fork and before spawning any threads.
* @param debugFlags bit flags that enable debugging features.
* @param rlimits null-ok an array of rlimit tuples, with the second
* dimension having a length of 3 and representing
* (resource, rlim_cur, rlim_max). These are set via the posix
* setrlimit(2) call.
* @param seInfo null-ok a string specifying SELinux information for
* the new process.
* @param niceName null-ok a string specifying the process name.
* @param fdsToClose an array of ints, holding one or more POSIX
* file descriptor numbers that are to be closed by the child
* (and replaced by /dev/null) after forking. An integer value
* of -1 in any entry in the array means "ignore this one".
* @param instructionSet null-ok the instruction set to use.
* @param appDataDir null-ok the data directory of the app.
*
* @return 0 if this is the child, pid of the child
* if this is the parent, or -1 on error.
*/
public static int Zygote::forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
String instructionSet, String appDataDir) {
VM_HOOKS.preFork();
int pid = nativeForkAndSpecialize(
uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
instructionSet, appDataDir);
// Enable tracing as soon as possible for the child process.
if (pid == 0) {
Trace.setTracingEnabled(true);
// Note that this event ends at the end of handleChildProc,
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
}
VM_HOOKS.postForkCommon();
return pid;
}
native private static int Zygote::nativeForkAndSpecialize(int uid, int gid, int[] gids,int debugFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
String instructionSet, String appDataDir);
我们知道Linux中的fork()比较特殊,它执行一次,但会返回两次:一是在子进程,二是在父进程。如果底层fork()子进程成功,并且当前处于子进程中,由前面的代码我们知道,此时会调用ZygoteConnection::handleChildProc()处理:
/**
* Handles post-fork setup of child proc, closing sockets as appropriate,
* reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller
* if successful or returning if failed.
*
* @param parsedArgs non-null; zygote args
* @param descriptors null-ok; new file descriptors for stdio if available.
* @param pipeFd null-ok; pipe for communication back to Zygote.
* @param newStderr null-ok; stream to use for stderr until stdio
* is reopened.
*
* @throws ZygoteInit.MethodAndArgsCaller on success to
* trampoline to code that invokes static main.
*/
private void ZygoteConnection::handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller {
/**
* By the time we get here, the native code has closed the two actual Zygote
* socket connections, and substituted /dev/null in their place. The LocalSocket
* objects still need to be closed properly.
*/
closeSocket();//关闭当前请求创建子进程的socket连接
ZygoteInit.closeServerSocket();//因为fork进程采用复制模式,而子进程本身又不要从父进程得到的"zygote" 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);
}
newStderr = System.err;
} 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) {//新进程启动参数中没有指定这一项
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.remainingArgs);
} else {//走else分支
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);//为新创建的进程初始化运行时库,启动Binder线程池
}
}
此时会关闭这次为创建子进程而连接的socket和从父进程Zygote复制得到的"zygote" socket;接着会为应用进程开启Binder线程池,这样应用进程就可以使用Binder通信了。
如果当前fork()是返回在父进程中,则会调用ZygoteConnection::handleParentProc()处理,其中就有将当前创建的子进程的pid通过输出流传给AMS请求端的操作:
/**
* Handles post-fork cleanup of parent proc
*
* @param pid != 0; pid of child if > 0 or indication of failed fork
* if < 0;
* @param descriptors null-ok; file descriptors for child's new stdio if
* specified.
* @param pipeFd null-ok; pipe for communication with child.
* @param parsedArgs non-null; zygote args
* @return true for "exit command loop" and false for "continue command
* loop"
*/
private boolean handleParentProc(int pid,
FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {
if (pid > 0) {
setChildPgid(pid);
}
if (descriptors != null) {
for (FileDescriptor fd: descriptors) {
IoUtils.closeQuietly(fd);
}
}
...
try {
mSocketOutStream.writeInt(pid);//将子进程的Pid返回给AMS请求端
mSocketOutStream.writeBoolean(usingWrapper);
} catch (IOException ex) {
Log.e(TAG, "Error writing to command socket", ex);
return true;
}
return false;
}
如果fork()过后是在子进程中,系统会为该应用进程开启Binder线程池,以让应用进程可以进行Binder通信;同时进入指定的进程入口函数。它由RuntimeInit::zygoteInit()处理: /**
* The main function called when started through the zygote process. This
* could be unified with main(), if the native code in nativeFinishInit()
* were rationalized with Zygote startup.<p>
*
* Current recognized args:
* <ul>
* <li> <code> [--] <start class name> <args>
* </ul>
*
* @param targetSdkVersion target SDK version
* @param argv arg strings
*/
public static final void RunntimeInit::zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
redirectLogStreams();
commonInit();//初始化一些通用的信息,如时区等
nativeZygoteInit();//为新应用/System进程启动一个Binder线程池
applicationInit(targetSdkVersion, argv, classLoader);//即将进入应用程序进程的入口函数:ActivityThread::main();如果是System进程,则它的入口函数是com.android.server.SystemServer::main()
}
nativeZygoteInit()是native函数,它的JNI实现是:static void AndroidRuntime::com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onZygoteInit();//gCurRuntime实际指向AndroidRuntime的子类AppRuntime实例,即调用AppRuntime::onZygoteInit();gCurRuntime是在创建Zygote进程之初创建的
}
看层次调用:
virtual void AppRuntime::onZygoteInit()
{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();//调用当前应用程序进程的ProcessState实例的startThreadPool()方法启动一个Binder线程池
}
每个进程都只有一个ProcessState实例,它描述了当前进程的一些信息,看ProcessState::startThreadPool():void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
spawnPooledThread(true);
}
}
void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
String8 name = makeBinderThreadName();
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
sp<Thread> t = new PoolThread(isMain);
t->run(name.string());
}
}
class PoolThread : public Thread
{
public:
PoolThread(bool isMain)
: mIsMain(isMain)
{
}
protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
const bool mIsMain;
};
void IPCThreadState::joinThreadPool(bool isMain)
{
LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
// This thread may have been spawned by a thread that was in the background
// scheduling group, so first we will make sure it is in the foreground
// one to avoid performing an initial transaction in the background.
set_sched_policy(mMyThreadId, SP_FOREGROUND);
status_t result;
do {
processPendingDerefs();
// now get the next command to be processed, waiting if necessary
result = getAndExecuteCommand();
if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
mProcess->mDriverFD, result);
abort();
}
// Let this thread exit the thread pool if it is no longer
// needed and it is not the main process thread.
if(result == TIMED_OUT && !isMain) {
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);
LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
(void*)pthread_self(), getpid(), (void*)result);
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}
由代码可知,一个进程创建后,只会初始化一次Binder线程池;Binder线程池的开启由IPCThreadState处理,它会与Binder驱动交互,处理进程内的Binder通信请求。再回到前面,看新创建的进程是如何进入指定的ActivityThread::main()入口函数的:
private static void ZygoteInit::applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
// 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;
try {
args = new Arguments(argv);
} catch (IllegalArgumentException ex) {
Slog.e(TAG, ex.getMessage());
// let the process exit
return;
}
// 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
invokeStaticMain(args.startClass, args.startArgs, classLoader);//如果是应用进程,它的入口函数进入ActivityThread::main();如果是System进程,则它的入口函数是com.android.server.SystemServer::main()
}
/**
* Invokes a static "main(argv[]) method on class "className".
* Converts various failing exceptions into RuntimeExceptions, with
* the assumption that they will then cause the VM instance to exit.
*
* @param className Fully-qualified class name
* @param argv Argument vector for main()
* @param classLoader the classLoader to load {@className} with
*/
private static void ZygoteInit::invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
Class<?> cl;
try {
cl = Class.forName(className, true, classLoader);//加载ActivityThread类到当前进程中,得到ActivityThread类的一个实例
} 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 });//获取到它的main()函数的Method对象
} 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.
*/
throw new ZygoteInit.MethodAndArgsCaller(m, argv);//抛出MethodAndArgsCaller异常,根据堆栈调用顺序,ZygoteInit::main()函数会捕获该异常:执行它的run(),如果是应用进程,调用ActivtyThread::main();如果是System进程,则它的入口函数是com.android.server.SystemServer::main()
}
主要处理,就是从创建进程时指定的参数中得到指定的入口函数,加载ActivityThread类,并通过反射获取到它内部的静态函数main()的Method对象;最后抛出ZygoteInit.MethodAndArgsCaller异常。
由于Android子进程的创建采用fork(),子进程会得到从父进程(zygote)复制得来的堆栈调用信息;Zygote进程的入口函数是ZygoteInit::main(),从前述的代码分析,并结合之前Zygote进程启动的流程分析也可知,整个过程中唯一会处理该异常的地方就是ZygoteInit::main():
//ZygoteInit::main:Zygote进程的入口函数
public static void main(String argv[]) {
// Mark zygote start. This ensures that thread creation will throw
// an error.
ZygoteHooks.startZygoteNoThreadCreation();
try {
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit");
RuntimeInit.enableDdms();
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;//需要启动system_server进程
} 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.");
}
registerZygoteSocket(socketName);//为"zygote" socket创建一个Server端监听套接字,用来监听AMS创建新应用进程的请求;"zygote"在init进程解析Zygote进程启动时就已经创建.
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload();//预加载一些通用的类/库/资源,以便在进程间共享
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
// Finish profiling the zygote initialization.
SamplingProfilerIntegration.writeZygoteSnapshot();
// Do an initial gc to clean up after startup
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PostZygoteInitGC");
gcAndFinalize();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false);
// Zygote process unmounts root storage spaces.
Zygote.nativeUnmountStorageOnInit();
ZygoteHooks.stopZygoteNoThreadCreation();
if (startSystemServer) {//Zygote进程启动时,设置了需要启动system_server进程的标志位
startSystemServer(abiList, socketName);//启动system_server进程
}
Log.i(TAG, "Accepting command socket connections");
runSelectLoop(abiList);//循环等待/处理来自AMS的创建新应用进程的请求
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();//会捕获MethodAndArgsCaller异常,并执行它的run();用来进入新的应用进程的主入口函数:ActivityThread::main();如果是System进程,则它的入口函数是com.android.server.SystemServer::main()
} catch (Throwable ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
调用MethodAndArgsCaller的run()函数:
/**
* Helper exception class which holds a method and arguments and
* can call them. This is used as part of a trampoline to get rid of
* the initial process setup stack frames.
*/
public static class ZygoteInit::MethodAndArgsCaller extends Exception
implements Runnable {
/** method to call */
private final Method mMethod;
/** argument array */
private final String[] mArgs;
public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}
public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });//调用ActivityThread::main()
} 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);
}
}
}
从前面分析得知,此时的处理就是通过反射调用ActivityThread::main(): //应用进程的入口函数
public static void ActivityThread::main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();//创建ActivityThread对象
thread.attach(false);//调用attach()向AMS发送一个进程启动完成通知
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();//开启消息循环
throw new RuntimeException("Main thread loop unexpectedly exited");
}
此时,会为应用程序初始化一些变量,并开启消息循环;这样ActivityThread作为应用进程的入口函数、作为应用主线程的初始化工作就完成了。此时,AMS创建应用子进程的整个过程也就分析完毕了。
PS:
对于采用ZygoteInit.MethodAndArgsCaller异常这种绕了一圈的方式来调用ActivityThread::main()的原因,这里摘一段罗大大的解释:
“AMS请求Zygote进程创建的应用程序的入口的函数为ActivityThread::main(),但是由于新创建的应用程序进程一开始就需要在内部初始化运行时库,以及启动Binder线程池,因此,当ActivityThread::main()被调用时,新创建的应用进程实际上已经执行了相当多的代码。为了使得新创建的应用程序进程感觉它的入口函数就是ActivityThread::main(),系统就不在AMS开始调用进程创建函数处调用,而是先抛出一个异常回到ZygoteInit::main()中,然后再间接地调用它,这样就可以巧妙地利用Java语言的异常处理机制来清理它前面的调用堆栈了。”