本文基于 Android 9.0 , 代碼倉庫地址 : android_9.0.0_r45
文中原始碼鏈接:
SystemServer.java
ActivityManagerService.java
Process.java
ZygoteProcess.java
對 Zygote 和 SystemServer 啟動流程還不熟悉的建議閱讀下面兩篇文章:
Java 世界的盤古和女媧 —— Zygote
Zygote 家的大兒子 —— SystemServer
Zygote 作為 Android 世界的受精卵,在成功繁殖出 system_server 行程之后并沒有完全功成身退,仍然承擔著受精卵的責任,Zygote 通過呼叫其持有的 ZygoteServer 物件的 runSelectLoop() 方法開始等待客戶端的呼喚,有求必應,客戶端的請求無非是創建應用行程,以 startActivity() 為例,假如開啟的是一個尚未創建行程的應用,那么就會向 Zygote 請求創建行程,下面將從 客戶端發送請求 和 服務端處理請求 兩方面來進行決議,
客戶端發送請求
startActivity() 的具體流程這里就不分析了,系列后續文章會寫到,我們直接看到創建行程的 startProcess() 方法,該方法在 ActivityManagerService 中,后面簡稱 AMS,
Process.startProcess()
> ActivityManagerService.java
private ProcessStartResult startProcess(String hostingType, String entryPoint,
ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
String seInfo, String requiredAbi, String instructionSet, String invokeWith,
long startTime) {
try {
checkTime(startTime, "startProcess: asking zygote to start proc");
final ProcessStartResult startResult;
if (hostingType.equals("webview_service")) {
startResult = startWebView(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
} else {
// 新建行程
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
}
checkTime(startTime, "startProcess: returned from zygote!");
return startResult;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
呼叫 Process.start() 方法新建行程,繼續追進去:
> Process.java
public static final ProcessStartResult start(
// android.app.ActivityThread,創建行程后會呼叫其 main() 方法
final String processClass,
final String niceName, // 行程名
int uid, int gid, int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith, // 一般新建應用行程時,此引數不為 null
String[] zygoteArgs) {
return zygoteProcess.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}
繼續呼叫 zygoteProcess.start() :
> ZygoteProess.java
public final Process.ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}
呼叫 startViaZygote() 方法,終于看到 Zygote 的身影了,
startViaZygote()
> ZygoteProcess.java
private Process.ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
boolean startChildZygote, // 是否克隆 zygote 行程的所有狀態
String[] extraArgs)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<String>();
// --runtime-args, --setuid=, --setgid=,
// and --setgroups= must go first
// 處理引數
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
argsForZygote.add("--runtime-flags=" + runtimeFlags);
if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
argsForZygote.add("--mount-external-default");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
argsForZygote.add("--mount-external-read");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
argsForZygote.add("--mount-external-write");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
// --setgroups is a comma-separated list
if (gids != null && gids.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--setgroups=");
int sz = gids.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(',');
}
sb.append(gids[i]);
}
argsForZygote.add(sb.toString());
}
if (niceName != null) {
argsForZygote.add("--nice-name=" + niceName);
}
if (seInfo != null) {
argsForZygote.add("--seinfo=" + seInfo);
}
if (instructionSet != null) {
argsForZygote.add("--instruction-set=" + instructionSet);
}
if (appDataDir != null) {
argsForZygote.add("--app-data-dir=" + appDataDir);
}
if (invokeWith != null) {
argsForZygote.add("--invoke-with");
argsForZygote.add(invokeWith);
}
if (startChildZygote) {
argsForZygote.add("--start-child-zygote");
}
argsForZygote.add(processClass);
if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}
synchronized(mLock) {
// 和 Zygote 行程進行 socket 通信
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
前面一大串代碼都是在處理引數,大致瀏覽即可,核心在于最后的 openZygoteSocketIfNeeded() 和 zygoteSendArgsAndGetResult() 這兩個方法,從方法命名就可以看出來,這里要和 Zygote 進行 socket 通信了,還記得 ZygoteInit.main() 方法中呼叫的 registerServerSocketFromEnv() 方法嗎?它在 Zygote 行程中創建了服務端 socket,
openZygoteSocketIfNeeded()
先來看看 openZygoteSocketIfNeeded() 方法,
> ZygoteProcess.java
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
// 未連接或者連接已關閉
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
// 開啟 socket 連接
primaryZygoteState = ZygoteState.connect(mSocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
maybeSetApiBlacklistExemptions(primaryZygoteState, false);
maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
}
if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}
// 當主 zygote 沒有匹配成功,嘗試 connect 第二個 zygote
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
try {
secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
}
maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
}
if (secondaryZygoteState.matches(abi)) {
return secondaryZygoteState;
}
throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}
如果與 Zygote 行程的 socket 連接未開啟,則嘗試開啟,可能會產生阻塞和重試,連接呼叫的是 ZygoteState.connect() 方法,ZygoteState 是 ZygoteProcess 的內部類,
> ZygoteProcess.java
public static class ZygoteState {
final LocalSocket socket;
final DataInputStream inputStream;
final BufferedWriter writer;
final List<String> abiList;
boolean mClosed;
private ZygoteState(LocalSocket socket, DataInputStream inputStream,
BufferedWriter writer, List<String> abiList) {
this.socket = socket;
this.inputStream = inputStream;
this.writer = writer;
this.abiList = abiList;
}
public static ZygoteState connect(LocalSocketAddress address) throws IOException {
DataInputStream zygoteInputStream = null;
BufferedWriter zygoteWriter = null;
final LocalSocket zygoteSocket = new LocalSocket();
try {
zygoteSocket.connect(address);
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 " + address.getNamespace() + "/"
+ address.getName() + " opened, supported ABIS: " + abiListString);
return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
Arrays.asList(abiListString.split(",")));
}
...
}
通過 socket 連接 Zygote 遠程服務端,
再回頭看之前的 zygoteSendArgsAndGetResult() 方法,
zygoteSendArgsAndGetResult()
> ZygoteProcess.java
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
try {
...
final BufferedWriter writer = zygoteState.writer;
final DataInputStream inputStream = zygoteState.inputStream;
writer.write(Integer.toString(args.size()));
writer.newLine();
// 向 zygote 行程發送引數
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
writer.write(arg);
writer.newLine();
}
writer.flush();
// 是不是應該有一個超時時間?
Process.ProcessStartResult result = new Process.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.
// 讀取 zygote 行程回傳的子行程 pid
result.pid = inputStream.readInt();
result.usingWrapper = inputStream.readBoolean();
if (result.pid < 0) { // pid 小于 0 ,fork 失敗
throw new ZygoteStartFailedEx("fork() failed");
}
return result;
} catch (IOException ex) {
zygoteState.close();
throw new ZygoteStartFailedEx(ex);
}
}
通過 socket 發送請求引數,然后等待 Zygote 行程回傳子行程 pid ,客戶端的作業到這里就暫時完成了,我們再追蹤到服務端,看看服務端是如何處理客戶端請求的,
Zygote 處理客戶端請求
Zygote 處理客戶端請求的代碼在 ZygoteServer.runSelectLoop() 方法中,
> ZygoteServer.java
Runnable runSelectLoop(String abiList) {
...
while (true) {
...
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;
}
if (i == 0) { // 有新客戶端連接
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else { // 處理客戶端請求
try {
ZygoteConnection connection = peers.get(i);
// fork 子行程,并回傳包含子行程 main() 函式的 Runnable 物件
final Runnable command = connection.processOneCommand(this);
if (mIsForkChild) {
// 位于子行程
if (command == null) {
throw new IllegalStateException("command == null");
}
return command;
} else {
// 位于父行程
if (command != null) {
throw new IllegalStateException("command != null");
}
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(i);
fds.remove(i);
}
}
} catch (Exception e) {
...
} finally {
mIsForkChild = false;
}
}
}
}
}
acceptCommandPeer() 方法用來回應新客戶端的 socket 連接請求,processOneCommand() 方法用來處理客戶端的一般請求,
processOneCommand()
> ZygoteConnection.java
Runnable processOneCommand(ZygoteServer zygoteServer) {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
// 1. 讀取 socket 客戶端發送過來的引數串列
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
throw new IllegalStateException("IOException on command socket", ex);
}
...
// 2. fork 子行程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
parsedArgs.instructionSet, parsedArgs.appDataDir);
try {
if (pid == 0) {
// 處于進子行程
zygoteServer.setForkChild();
// 關閉服務端 socket
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
// 3. 處理子行程事務
return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.startChildZygote);
} else {
// 處于 Zygote 行程
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
// 4. 處理父行程事務
handleParentProc(pid, descriptors, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
processOneCommand() 方法大致可以分為五步,下面逐步分析,
readArgumentList()
> ZygoteConnection.java
private String[] readArgumentList()
throws IOException {
int argc;
try {
// 逐行讀取引數
String s = mSocketReader.readLine();
if (s == null) {
// EOF reached.
return null;
}
argc = Integer.parseInt(s);
} catch (NumberFormatException ex) {
throw new IOException("invalid wire format");
}
// See bug 1092107: large argc can be used for a DOS attack
if (argc > MAX_ZYGOTE_ARGC) {
throw new IOException("max arg count exceeded");
}
String[] result = new String[argc];
for (int i = 0; i < argc; i++) {
result[i] = mSocketReader.readLine();
if (result[i] == null) {
// We got an unexpected EOF.
throw new IOException("truncated request");
}
}
return result;
}
讀取客戶端發送過來的請求引數,
forkAndSpecialize()
> Zygote.java
public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) {
VM_HOOKS.preFork();
// Resets nice priority for zygote process.
resetNicePriority();
int pid = nativeForkAndSpecialize(
uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
fdsToIgnore, startChildZygote, instructionSet, appDataDir);
// Enable tracing as soon as possible for the child process.
if (pid == 0) {
Trace.setTracingEnabled(true, runtimeFlags);
// Note that this event ends at the end of handleChildProc,
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
}
VM_HOOKS.postForkCommon();
return pid;
}
nativeForkAndSpecialize() 是一個 native 方法,在底層 fork 了一個新行程,并回傳其 pid,不要忘記了這里的 一次fork,兩次回傳 ,pid > 0 說明還是父行程,pid = 0 說明進入了子行程,子行程中會呼叫 handleChildProc,而父行程中會呼叫 handleParentProc(),
handleChildProc()
> ZygoteConnection.java
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd, boolean isZygote) {
closeSocket(); // 關閉 socket 連接
...
if (parsedArgs.niceName != null) {
// 設定行程名
Process.setArgV0(parsedArgs.niceName);
}
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 {
if (!isZygote) { // 新建應用行程時 isZygote 引數為 false
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
null /* classLoader */);
} else {
return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
}
當看到 ZygoteInit.zygoteInit() 時你應該感覺很熟悉了,接下來的流程就是:
ZygoteInit.zygoteInit()→RuntimeInit.applicationInit()→findStaticMain()
和 SystemServer 行程的創建流程一致,這里要找的 main 方法就是 ActivityThrad.main() ,ActivityThread 雖然并不是一個執行緒,但你可以把它理解為應用的主執行緒,
handleParentProc()
> ZygoteConnection.java
private void handleParentProc(int pid, FileDescriptor[] descriptors, FileDescriptor pipeFd) {
if (pid > 0) {
setChildPgid(pid);
}
if (descriptors != null) {
for (FileDescriptor fd: descriptors) {
IoUtils.closeQuietly(fd);
}
}
boolean usingWrapper = false;
if (pipeFd != null && pid > 0) {
int innerPid = -1;
try {
// Do a busy loop here. We can't guarantee that a failure (and thus an exception
// bail) happens in a timely manner.
final int BYTES_REQUIRED = 4; // Bytes in an int.
StructPollfd fds[] = new StructPollfd[] {
new StructPollfd()
};
byte data[] = new byte[BYTES_REQUIRED];
int remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS;
int dataIndex = 0;
long startTime = System.nanoTime();
while (dataIndex < data.length && remainingSleepTime > 0) {
fds[0].fd = pipeFd;
fds[0].events = (short) POLLIN;
fds[0].revents = 0;
fds[0].userData = https://www.cnblogs.com/bingxinshuo/p/null;
int res = android.system.Os.poll(fds, remainingSleepTime);
long endTime = System.nanoTime();
int elapsedTimeMs = (int)((endTime - startTime) / 1000000l);
remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS - elapsedTimeMs;
if (res > 0) {
if ((fds[0].revents & POLLIN) != 0) {
// Only read one byte, so as not to block.
int readBytes = android.system.Os.read(pipeFd, data, dataIndex, 1);
if (readBytes < 0) {
throw new RuntimeException("Some error");
}
dataIndex += readBytes;
} else {
// Error case. revents should contain one of the error bits.
break;
}
} else if (res == 0) {
Log.w(TAG, "Timed out waiting for child.");
}
}
if (dataIndex == data.length) {
DataInputStream is = new DataInputStream(new ByteArrayInputStream(data));
innerPid = is.readInt();
}
if (innerPid == -1) {
Log.w(TAG, "Error reading pid from wrapped process, child may have died");
}
} catch (Exception ex) {
Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);
}
// Ensure that the pid reported by the wrapped process is either the
// child process that we forked, or a descendant of it.
if (innerPid > 0) {
int parentPid = innerPid;
while (parentPid > 0 && parentPid != pid) {
parentPid = Process.getParentPid(parentPid);
}
if (parentPid > 0) {
Log.i(TAG, "Wrapped process has pid " + innerPid);
pid = innerPid;
usingWrapper = true;
} else {
Log.w(TAG, "Wrapped process reported a pid that is not a child of "
+ "the process that we forked: childPid=" + pid
+ " innerPid=" + innerPid);
}
}
}
try {
mSocketOutStream.writeInt(pid);
mSocketOutStream.writeBoolean(usingWrapper);
} catch (IOException ex) {
throw new IllegalStateException("Error writing to command socket", ex);
}
}
主要進行一些資源清理的作業,到這里,子行程就創建完成了,
總結

- 呼叫
Process.start()創建應用行程 ZygoteProcess負責和Zygote行程建立 socket 連接,并將創建行程需要的引數發送給 Zygote 的 socket 服務端Zygote服務端接收到引數之后呼叫ZygoteConnection.processOneCommand()處理引數,并 fork 行程- 最后通過
findStaticMain()找到ActivityThread類的 main() 方法并執行,子行程就啟動了
預告
到現在為止已經決議了 Zygote 行程 ,SystemServer 行程,以及應用行程的創建,下一篇的內容是和應用最密切相關的系統服務 ActivityManagerService , 來看看它在 SystemServer 中是如何被創建和啟動的,敬請期待!
文章首發微信公眾號:
秉心說, 專注 Java 、 Android 原創知識分享,LeetCode 題解,更多最新原創文章,掃碼關注我吧!

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/55654.html
標籤:Android
上一篇:Android開發——RecyclerView實作下載串列
下一篇:Android 開發涼了嗎!
