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語言的異常處理機制來清理它前面的調用堆棧了。”