Android 8.1 zygote創建新應用進程
涉及到的文件以及路徑:
frameworks/base/core/java/com/android/internal/os/Zygote.java
frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
分析過Android系統啓動流程的同學都知道,zygote啓動之後,會調用ZygoteInit.java中的main函數。
ZygoteInit.java的路徑: frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
這個main函數如下:
public static void main(String argv[]) {
// 創建一個ZygoteServer 對象,這個是8.0 之後纔有的
// 這個就是zygote最後等待ActivityManager 連接來 fork新進程的地方
ZygoteServer zygoteServer = new ZygoteServer();
// Mark zygote start. This ensures that thread creation will throw
// an error.
// 調用native函數,確保當前沒有其它線程在運行
// 主要還是處於安全的考慮
// 啓動無多線程模式 .當在zygoteInit中新建線程系統掛掉
// 主要是由於擔心用戶新建線程提高預加載速度
// 但是可能沒做好同步工作, 當有的應用需要預加載的資源,但是多線程情況下還沒有加載,發生問題
ZygoteHooks.startZygoteNoThreadCreation();
// Zygote goes into its own process group.
// 指定當前進程的id(第一個參數是目標進程id,第二個參數是進程組id,把第二個參數設置成第一個的值)
try {
Os.setpgid(0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}
final Runnable caller;
try { // 解析上面傳遞過來的參數
// Report Zygote start time to tron unless it is a runtime restart
if (!"1".equals(SystemProperties.get("sys.boot_completed"))) { // 如果是重啓sys.boot_completed值是1
//上報Zygote進程啓動的時間
MetricsLogger.histogram(null, "boot_zygote_init",(int) SystemClock.elapsedRealtime());
}
String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,Trace.TRACE_TAG_DALVIK);
bootTimingsTraceLog.traceBegin("ZygoteInit");
RuntimeInit.enableDdms();
boolean startSystemServer = false; // 是否啓動 SystemServer
String socketName = "zygote"; // 創建的socket的名稱
String abiList = null; // 支持的so庫的類型
boolean enableLazyPreload = false; // 這個尚不清楚,不過傳遞過來的參數中沒有這個
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true;
} 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.");
}
zygoteServer.registerServerSocket(socketName); // 註冊server socket
// In some configurations, we avoid preloading resources and classes eagerly.
// In such cases, we will preload things prior to our first fork.
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
}
// Do an initial gc to clean up after startup
bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
gcAndFinalize();
bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
bootTimingsTraceLog.traceEnd(); // ZygoteInit
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false, 0);
// Zygote process unmounts root storage spaces.
// // 卸載root的存儲空間
Zygote.nativeUnmountStorageOnInit();
// Set seccomp policy
// Set seccomp policy
// 加載seccomp的過濾規則
// 所有 Android 軟件都使用系統調用(簡稱爲 syscall)與 Linux 內核進行通信
// 內核提供許多特定於設備和SOC的系統調用,讓用戶空間進程(包括應用)可以直接與內核進行交互
// 不過,其中許多系統調用Android未予使用或未予正式支持
// 通過seccomp,Android可使應用軟件無法訪問未使用的內核系統調用
// 由於應用無法訪問這些系統調用,因此,它們不會被潛在的有害應用利用
// 該過濾器安裝到zygote進程中,由於所有Android應用均衍生自該進程
// 因而會影響到所有應用
Seccomp.setPolicy();
ZygoteHooks.stopZygoteNoThreadCreation(); // 允許有其他線程了
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, socketName, zygoteServer); // 啓動SystemServer
// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
if (r != null) {
r.run(); // 這裏會調用到 RuntimeInit.java 中的 MethodAndArgsCaller 的 run方法,來正式進入 SystemServer的main函數
return;
}
}
Log.i(TAG, "Accepting command socket connections");
// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
caller = zygoteServer.runSelectLoop(abiList); // zygote進程進入無限循環,處理請求
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
Log.i(TAG, "zygoteServer.closeServerSocket finally finally");
// 這個地方有兩個調用的流程
// 1: zygote 進程退出的時候會調用這個函數,用來關閉zygote自己創建的用來接收ActivityManager的鏈接請求的socket
// 2:當每個子線程fork完畢,準備好之後,會走到這裏,這個時候會在子進程中執行的,這裏會調用closeServerSocket函數,確保從zygote集成過來的socket關閉。
// 其實這個時候,因爲子進程剛剛fock出來的時候就已經掉用過closeServerSocket函數了,因此再次調用,是沒有效果的
zygoteServer.closeServerSocket();
}
// We're in the child process and have exited the select loop. Proceed to execute the
// command.
if (caller != null) {
caller.run(); // 這裏纔是重點,上面會返回一個Runnable的對象,這個地方調用他的 run函數會進入到子進程的真正的main函數裏面
}
}
這個main函數中,首選會創建一個ZygoteServer對象,這個就是用來處理後續zygote socket連接的地方。然後會解析前面傳遞進來的參數。根據參數決定是否啓動SystemServer,啓動SystemServer的部分,網上比較多,這裏就不做詳細介紹了。
根據代碼流程我們會發現,在main函數的最後會調用 caller = zygoteServer.runSelectLoop(abiList);進入到ZygoteServer類的runSelectLoop函數中。下面我們就着重分析下這個函數的具體實現。
/**
* 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.
*/
Runnable runSelectLoop(String abiList) {
// 記錄需要監聽的句柄
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
// 記錄上面監聽的句柄所對應的處理類的實例對象
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
fds.add(mServerSocket.getFileDescriptor());
peers.add(null); // 這裏add null 是爲了使得它的index 和 fds 的index想對應。
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
Os.poll(pollFds, -1); // 開始進入監聽模式 無論是監聽到 連接請求還是 數據過來,這個函數都會返回
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) { // 根據監聽到的消息長度,循環處理監聽到的所有消息
if ((pollFds[i].revents & POLLIN) == 0) { // 無效消息,跳過
continue;
}
Slog.e(TAG, "runSelectLoop i = "+i+" mIsForkChild = "+mIsForkChild);
if (i == 0) { // 如果 i是0,就說明監聽到了連接請求,
// 此時調用 acceptCommandPeer 函數,這個函數會調用 mServerSocket.accept() 接受連接,並返回句柄
// 然後用此句柄爲參數創建了 ZygoteConnection 對象,然後由 ZygoteConnection 對象負責這一個連接的後續數據處理
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer); // 添加到 peers 這個
fds.add(newPeer.getFileDesciptor()); // 添加到 fds,然後在下次循環的時候,將剛剛接受的鏈接請求也一同添加到監聽
} else { // 如果不是0.那就是上面 i=0的時候接受到的連接發來數據了。
try {
ZygoteConnection connection = peers.get(i); // 從剛剛記錄的peers中獲取處理對應數據的 ZygoteConnection 類
final Runnable command = connection.processOneCommand(this);
// 因爲上面的 processOneCommand 函數調用中,如果創建了新的進程,上面的函數就會有兩個返回,
// 第一個是父進程的正常返回 此時的返回值是 null,還是在zygote進程中運行,並且mIsForkChild的值是沒有變的,這個時候會進入到else中
// 第二個返回時子進程的返回 此時的返回時不是空,此時是在子進程中運行,並且在子進程剛剛創建的時候,就將自己的mIsForkChild設置爲 true了。
if (mIsForkChild) {
// We're in the child. We should always have a command to run at this
// stage if processOneCommand hasn't called "exec".
// 這裏是在子進程
if (command == null) {
throw new IllegalStateException("command == null");
}
return command;
} else {
// We're in the server - we should never have any commands to run.
// 這裏是在父進程中
if (command != null) {
throw new IllegalStateException("command != null");
}
// We don't know whether the remote side of the socket was closed or
// not until we attempt to read from it from processOneCommand. This shows up as
// a regular POLLIN event in our regular processing loop.
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(i);
fds.remove(i);
}
}
} catch (Exception e) {
if (!mIsForkChild) {
// We're in the server so any exception here is one that has taken place
// pre-fork while processing commands or reading / writing from the
// control socket. Make a loud noise about any such exceptions so that
// we know exactly what failed and why.
Slog.e(TAG, "Exception executing zygote command: ", e);
// Make sure the socket is closed so that the other end knows immediately
// that something has gone wrong and doesn't time out waiting for a
// response.
ZygoteConnection conn = peers.remove(i);
conn.closeSocket();
fds.remove(i);
} else {
// We're in the child so any exception caught here has happened post
// fork and before we execute ActivityThread.main (or any other main()
// method). Log the details of the exception and bring down the process.
Log.e(TAG, "Caught post-fork exception in child process.", e);
throw e;
}
}
}
}
}
}
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
這個函數首先創建兩個鏈表,第一個鏈表 fds 是用來保存要監聽的socket文件描述符。
第二個鏈表peers用來保存對應的socket文件上的事件處理函數
另外 fds 和 peers 中元素是有對應關鍵的,即:fds中的第i個元素所對應的處理類就是peers中的第i個元素。這個後面的代碼中可以看出來
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
這裏將mServerSocket.getFileDescriptor()添加到fds裏面,就是將zygote自己創建的用來監聽ActivityManager連接的socket添加到fds鏈表裏面。因爲這個socket上沒有對應的事件處理類,因此其對應的peers中的處理類對象設置爲null
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {// 填充pollFds
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
Os.poll(pollFds, -1); // 開始進入監聽模式 無論是監聽到 連接請求還是 數據過來,這個函數都會返回
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
上面這個部分代碼就是每次循環都會 根據 fds 的大小重新建立pollFds,然後開始監聽。
// 上面的函數一旦監聽到動作就會返回,然後執行下面的代碼
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
// 上面根據監聽的pollFds的長度,循環從後到前,依次判斷是哪個句柄上存在數據,獲取存在數據的句柄
if (i == 0) { // 如果i等於0,就說明是zygote的socket上監聽到了連接請求。
// 對於新的鏈接請求,這裏會調用 acceptCommandPeer 函數,這個函數會調用 mServerSocket.accept() 接受連接,並返回句柄
// 然後用此句柄爲參數創建了 ZygoteConnection 對象,然後由 ZygoteConnection 對象負責這一個連接的後續數據處理
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer); // 將新創建的ZygoteConnection添加到 peers 這個列表中
fds.add(newPeer.getFileDesciptor()); // 添加到 fds,然後在下次循環的時候,將剛剛接受的鏈接請求也一同添加到監聽。
} else { // 如果i不是0.就說明是已將連接的socket上有數據發送過來了
ZygoteConnection connection = peers.get(i); // 從剛剛記錄的peers中獲取處理對應數據的 ZygoteConnection 類
final Runnable command = connection.processOneCommand(this); // 調用processOneCommand 函數處理socket發送過來的數據。
if (mIsForkChild) { // 由於前面processOneCommand函數很可能會創建新的進程,因此當再次返回這裏的時候,有可能會有兩個進程這裏就需要判斷是在那個進程中
// 這裏是在子進程。表示在processOneCommand中fork了新的進程,此時返回來的時候,新的進程會設置 mIsForkChild 標誌位
if (command == null) {
throw new IllegalStateException("command == null");
}
return command;
} else {
// 這裏是在父進程中。表示的時候 zygote 進程,
// 下面會關閉socket,並且將此socket的文件句柄,以及對應的處理類從鏈表中移除。
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(i);
fds.remove(i);
}
}
}
}
下面我們看下acceptCommandPeer函數的具體實現:
/**
* Waits for and accepts a single command connection. Throws
* RuntimeException on failure.
// socket編程中,accept()調用主要用在基於連接的套接字類型,比如SOCK_STREAM和SOCK_SEQPACKET
// 它提取出所監聽套接字的等待連接隊列中第一個連接請求,創建一個新的套接字,並返回指向該套接字的文件描述符
// 新建立的套接字不在監聽狀態,原來所監聽的套接字的狀態也不受accept()調用的影響
// 從代碼,可以看出 acceptCommandPeer 調用了server socket的accpet函數。於是當新的連接建立時,
// zygote將會創建出一個新的socket與其通信,並將該socket加入到fds中。因此,一旦通信連接建立後,fds中將會包含有多個socket
*/
private ZygoteConnection acceptCommandPeer(String abiList) {
try {
// 注意這裏的參數中調用了 mServerSocket.accept()
return createNewConnection(mServerSocket.accept(), abiList);
} catch (IOException ex) {
throw new RuntimeException(
"IOException during accept()", ex);
}
}
protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
throws IOException {
// 這裏根據參數,直接創建ZygoteConnection類對象
return new ZygoteConnection(socket, abiList);
}
下面是ZygoteConnection的構造函數
/**
* 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;
}
isEof = false;
}
上面的代碼流程很清晰,就是創建了一個ZygoteConnection對象。這個對象是用來處理這個socket具體發送過來的數據的。
下面我們在看下processOneCommand函數的具體實現。看看ZygoteConnection類中的processOneCommand函數都幹了什麼。
/**
* Reads one start command from the command socket. If successful, a child is forked and a
* {@code Runnable} that calls the childs main method (or equivalent) is returned in the child
* process. {@code null} is always returned in the parent process (the zygote).
*
* If the client closes the socket, an {@code EOF} condition is set, which callers can test
* for by calling {@code ZygoteConnection.isClosedByPeer}.
*/
Runnable processOneCommand(ZygoteServer zygoteServer) {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
args = readArgumentList(); // 從socket 中讀取傳遞過來的各種參數
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
throw new IllegalStateException("IOException on command socket", ex);
}
// readArgumentList returns null only when it has reached EOF with no available
// data to read. This will only happen when the remote socket has disconnected.
if (args == null) {
isEof = true;
return null;
}
int pid = -1;
FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null;
// parsedArgs 這個類是個工具類,主要是保存 並解析上面傳遞的參數,並保存解析的結果
// 這裏根據讀取到的數據,來構建Arguments類,這個類會解析傳遞過來的數據,並保存解析的結果
parsedArgs = new Arguments(args);
if (parsedArgs.abiListQuery) { // 查詢 AbiList
handleAbiListQuery();
return null;
}
if (parsedArgs.preloadDefault) { // 加載,並返回結果
handlePreload();
return null;
}
if (parsedArgs.preloadPackage != null) { // 預加載,
handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs,
parsedArgs.preloadPackageCacheKey);
return null;
}
if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
throw new ZygoteSecurityException("Client may not specify capabilities: " +
"permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));
}
// 安全檢查
applyUidSecurityPolicy(parsedArgs, peer);
applyInvokeWithSecurityPolicy(parsedArgs, peer);
applyDebuggerSystemProperty(parsedArgs);
applyInvokeWithSystemProperty(parsedArgs);
int[] fdsToIgnore = null;
Log.e(TAG, " processOneCommand parsedArgs.invokeWith = "+parsedArgs.invokeWith);
if (parsedArgs.invokeWith != null) { // 這裏好像一直都是空的,因此這裏進不去
try {
FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC); // 獲取管道通訊的兩端
childPipeFd = pipeFds[1]; // 寫入端
serverPipeFd = pipeFds[0]; // 讀取端
Os.fcntlInt(childPipeFd, F_SETFD, 0);
fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
} catch (ErrnoException errnoEx) {
throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx);
}
}
/**
* In order to avoid leaking descriptors to the Zygote child,
* the native code must close the two Zygote socket descriptors
* in the child process before it switches from Zygote-root to
* the UID and privileges of the application being launched.
*
* In order to avoid "bad file descriptor" errors when the
* two LocalSocket objects are closed, the Posix file
* descriptors are released via a dup2() call which closes
* the socket and substitutes an open descriptor to /dev/null.
*/
int [] fdsToClose = { -1, -1 };
FileDescriptor fd = mSocket.getFileDescriptor();
if (fd != null) {
fdsToClose[0] = fd.getInt$();
}
fd = zygoteServer.getServerSocketFileDescriptor();
if (fd != null) {
fdsToClose[1] = fd.getInt$();
}
fd = null;
// 創建子進程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
parsedArgs.appDataDir);
try {
if (pid == 0) {
// in child
// 因爲子進程是複製於父進程,因此在子進程中 他的 mIsForkChild 值依然是父進程的原始值,false
// 此時調用 setForkChild 只會設置子進程中的 mIsForkChild 變量的值,
zygoteServer.setForkChild(); //設置標誌.這樣在這個地方返回的時候,zygoteServer 就會走到子進程的處理函數中了
zygoteServer.closeServerSocket(); // 關閉子線程中的 socket,這個socket是從zygote集成過來的,因此這裏需要首選關閉掉。
IoUtils.closeQuietly(serverPipeFd); // 關閉流
serverPipeFd = null;
return handleChildProc(parsedArgs, descriptors, childPipeFd);
} 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);
}
}
這個函數的流程比較簡單,首先讀取對端發送過來的數據,然後根據發送過來的數據構建Arguments這個類,這類會解析傳遞過來的參數,並保存解析的結果。然後根據解析情況進行各種判斷。然後調用Zygote.forkAndSpecialize創建新的進程,這個函數會有兩次返回,第一次是在原來的父進程中返回,第二次是在新創建的子進程中返回。從這個函數返回起,子進程和父進程就分道揚鑣了,這個時候,我們需要注意下自己看的這部分代碼是在子線程中還是在父進程中。
下面我們在貼下forkAndSpecialize函數的代碼
public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
int[] fdsToIgnore, String instructionSet, String appDataDir) {
VM_HOOKS.preFork(); // 這裏會等待zygote的所有子線程都退出即:停止Zyote的4個Daemon子線程的運行,初始化gc堆
// Resets nice priority for zygote process.
resetNicePriority(); // 設置zygote進程的優先級爲 normal
int pid = nativeForkAndSpecialize(
uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
fdsToIgnore, instructionSet, appDataDir);
// Enable tracing as soon as possible for the child process.
if (pid == 0) {
// 子進程中
Trace.setTracingEnabled(true, debugFlags);
// Note that this event ends at the end of handleChildProc,
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
}
VM_HOOKS.postForkCommon(); // 啓動4個Deamon子線程
return pid;
}
下面我們看下handleChildProc函數的大體流程
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd) {
closeSocket(); // 關閉socket。這個socket 根前面剛剛關閉的socket不是同一個
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);
// Should not get here.
throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
} else { // 這裏調用 ZygoteInit.zygoteInit 進一步初始化
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
null /* classLoader */);
}
}
下面我們看下ZygoteInit.zygoteInit的實現
// 這個函數是一個公共的函數,啓動 systemServer 以及啓動 應用都會調用到這裏
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");
RuntimeInit.redirectLogStreams(); // 將system.out 以及System.err 的輸出重定向到 Android log中
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit(); // 初始化native層
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
下面是applicationInit函數的實現
protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {
// 如果應用調用System.exit()直接終結一個進程,但是沒有調用 shutdown hooks,這個對於一個Android應用了來說確實可以
// 但是shutdown hooks是用來關閉Binder的,如果沒有調用,會導致一些線程遺留,造成crash
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); // 設置sdk版本
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);
}
這個findStaticMain函數會根據傳遞的參數,找到對應的java類的靜態main函數,然後 通過return new MethodAndArgsCaller(m, argv);來返回一個MethodAndArgsCaller類,下面我們看下MethodAndArgsCaller類的實現。
static class MethodAndArgsCaller 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 }); //這個會調用相應的方法並將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);
}
}
}
這個類的實現很簡單,就是保存要啓動的函數對象,已經要傳遞的參數,然後提供一個 run函數來執行對應的函數並傳遞參數給這個函數。如果這裏調用的是 SystemServer,那麼這裏就會調用SystemServer.java的main函數,如果是啓動的應用,那就會調用ActivityThread.java 的main函數。
但是上面的findStaticMain並沒有調用這個run函數,而是僅僅創建了一個類對象,然後就將這個對象返回了。那麼這個函數是在哪裏調用的呢,這裏就一層一層的返回了,首先這裏會返回到ZygoteConnection.java的processOneCommand 函數,然後這個函數接着返回,會返回到ZygoteServer.java中的runSelectLoop函數中,在這個函數有下面的代碼:
if (mIsForkChild) {
// We're in the child. We should always have a command to run at this
// stage if processOneCommand hasn't called "exec".
// 這裏是在子進程
if (command == null) {
throw new IllegalStateException("command == null");
}
return command; // 這裏再次返回
}
上面的代碼會繼續返回到ZygoteInit.java中的main函數中;下面這部分代碼就會main函數的處理函數。
// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
caller = zygoteServer.runSelectLoop(abiList); // zygote進程進入無限循環,處理請求
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
Log.i(TAG, "zygoteServer.closeServerSocket finally finally");
// 這個地方有兩個調用的流程
// 1: zygote 進程退出的時候會調用這個函數,用來關閉zygote自己創建的用來接收ActivityManager的鏈接請求的socket
// 2:當每個子線程fork完畢,準備好之後,會走到這裏,這個時候會在子進程中執行的,這裏會調用closeServerSocket函數,確保從zygote集成過來的socket關閉。
// 其實這個時候,因爲子進程剛剛fock出來的時候就已經掉用過closeServerSocket函數了,因此再次調用,是沒有效果的
zygoteServer.closeServerSocket();
}
// We're in the child process and have exited the select loop. Proceed to execute the
// command.
if (caller != null) {
caller.run(); // 這裏纔是重點,上面會返回一個Runnable的對象,這個地方調用他的 run函數會進入到子進程的真正的main函數裏面
}
上面的這段代碼,當zygoteServer.runSelectLoop返回的時候,就已經是在子進程中了,此時會在後面調用caller.run();來執行對應的java文件的main函數。至此zygote中啓動新進程的流程就梳理完成了。