Android應(yīng)用進(jìn)程的創(chuàng)建
在之前的Android啟動流程中,我們最后提到了會通過ActivityManagerService的startProcess方法來進(jìn)行應(yīng)用進(jìn)程的創(chuàng)建。本篇文章我們就從這里開始著手,來進(jìn)行相關(guān)源碼的解析工作。
ActivityManagerService#startProcess
//ActivityManagerService#LocalService.java
public void startProcess(String processName, ApplicationInfo info,
boolean knownToBeDead, String hostingType, ComponentName hostingName) {
try {
//同步操作,避免死鎖
synchronized (ActivityManagerService.this) {
//調(diào)用startProcessLocked方法, Process的start,最終到ZygoteProcess的attemptUsapSendArgsAndGetResult()
// 用來fork一個新的Launcher的進(jìn)程
startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,new HostingRecord(hostingType, hostingName),false /* allowWhileBooting */, false /* isolated */,true /* keepIfLarge */);
}
...
}
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
HostingRecord hostingRecord, boolean allowWhileBooting,
boolean isolated, boolean keepIfLarge) {
return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
hostingRecord, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
null /* crashHandler */);
}
這里最終調(diào)用了ProcessList的startProcessLocked方法。這里的ProcessList類的主要作用是用來處理進(jìn)程。
ProcessList#startProcessLocked
//啟動進(jìn)程
@GuardedBy("mService")
boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
boolean disableHiddenApiChecks, boolean mountExtStorageFull,
String abiOverride) {
//已經(jīng)啟動,則直接返回
if (app.pendingStart) {
return true;
}
//啟動時間
long startTime = SystemClock.elapsedRealtime();
...
//設(shè)置程序的入口
final String entryPoint = "android.app.ActivityThread";
//***重點方法****
return startProcessLocked(hostingRecord, entryPoint, app, uid, gids,
runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
startTime);
...
}
調(diào)用了一個重載方法,注意我們這里的一個參數(shù)entryPoint,這個是我們的進(jìn)程啟動以后的入口類,當(dāng)我們fork出進(jìn)程以后,會調(diào)用這個類中的main方法來啟進(jìn)程。
boolean startProcessLocked(HostingRecord hostingRecord,
String entryPoint,
ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
String seInfo, String requiredAbi, String instructionSet, String invokeWith,
long startTime) {
...
//***重點方法***
final Process.ProcessStartResult startResult = startProcess(app.hostingRecord,
entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal,
app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime);
...
}
private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
String seInfo, String requiredAbi, String instructionSet, String invokeWith,
long startTime) {
//*****重點方法*****最終調(diào)用的創(chuàng)建進(jìn)程的方法
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, app.info.packageName,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
}
最后將進(jìn)程的創(chuàng)建交給Process類來進(jìn)行處理,通過start方法創(chuàng)建,然后返回了ProcessStartResult啟動的結(jié)果。
Process#start
public static ProcessStartResult start(@NonNull final String processClass,
@Nullable final String niceName,
int uid, int gid, @Nullable int[] gids,
int runtimeFlags,
int mountExternal,
int targetSdkVersion,
@Nullable String seInfo,
@NonNull String abi,
@Nullable String instructionSet,
@Nullable String appDataDir,
@Nullable String invokeWith,
@Nullable String packageName,
@Nullable String[] zygoteArgs) {
//processClass為"android.app.ActivityThread",表示程序的入口類
return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
/*useUsapPool=*/ true, zygoteArgs);
}
調(diào)用ZygoteProcess的start方法
ZygoteProcess#start
//啟動一個新的進(jìn)程
public final Process.ProcessStartResult start(@NonNull final String processClass,
final String niceName,
int uid, int gid, @Nullable int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
@Nullable String seInfo,
@NonNull String abi,
@Nullable String instructionSet,
@Nullable String appDataDir,
@Nullable String invokeWith,
@Nullable String packageName,
boolean useUsapPool,
@Nullable String[] zygoteArgs) {
try {
//***重點方法****
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
packageName, useUsapPool, zygoteArgs);
}
...
}
private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,
@Nullable final String niceName,
final int uid, final int gid,
@Nullable final int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
@Nullable String seInfo,
@NonNull String abi,
@Nullable String instructionSet,
@Nullable String appDataDir,
@Nullable String invokeWith,
boolean startChildZygote,
@Nullable String packageName,
boolean useUsapPool,
@Nullable String[] extraArgs)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<>();
//這是一些創(chuàng)建進(jìn)程時候的參數(shù)信息
...
//這個是程序的入口類,設(shè)置的是"android.app.ActivityThread"
argsForZygote.add(processClass);
...
synchronized(mLock) {
//***重點方法***
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
useUsapPool,
argsForZygote);
}
}
openZygoteSocketIfNeeded 會創(chuàng)建一個和Zygote的socket連接。
//如果初始的Zygote的連接不存在或者未連接。則創(chuàng)建一個Socket連接,并將相關(guān)信息封裝為ZygoteState
@GuardedBy("mLock")
private void attemptConnectionToPrimaryZygote() throws IOException {
//如果沒有連接
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
primaryZygoteState = ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);
}
}
如果之前沒有建立過和Zygote之間的連接,那么會通過connect()方法進(jìn)行連接
static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress,@Nullable LocalSocketAddress usapSocketAddress)throws IOException {
DataInputStream zygoteInputStream;
BufferedWriter zygoteOutputWriter;
final LocalSocket zygoteSessionSocket = new LocalSocket();
try {
//進(jìn)行連接
zygoteSessionSocket.connect(zygoteSocketAddress);
//創(chuàng)建DataInputStream
zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream());
//創(chuàng)建BufferedWriter
zygoteOutputWriter = new BufferedWriter(new OutputStreamWriter(zygoteSessionSocket.getOutputStream()),Zygote.SOCKET_BUFFER_SIZE);
...
//封裝為ZygoteState對象
return new ZygoteState(zygoteSocketAddress, usapSocketAddress,
zygoteSessionSocket, zygoteInputStream, zygoteOutputWriter,
getAbiList(zygoteOutputWriter, zygoteInputStream));
}
所以openZygoteSocketIfNeeded的主要作用是保證和Zygote的socket連接的存在。當(dāng)連接存在以后就可以通過socket進(jìn)行消息的傳輸了。
ZygoteProcess#zygoteSendArgsAndGetResult
通過socket連接Zygote,并發(fā)送對應(yīng)的fork進(jìn)程所需要的信息
private Process.ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, boolean useUsapPool, @NonNull ArrayList<String> args) throws ZygoteStartFailedEx {
//****重點方法**** 嘗試fork子線程
return attemptZygoteSendArgsAndGetResult(zygoteState, msgStr);
}
private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(
ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {
try {
//傳入的zygoteState為openZygoteSocketIfNeeded(),里面會通過abi來檢查是第一個zygote還是第二個
final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
//將參數(shù)的信息寫給Zygote進(jìn)程,包括前面的processClass ="android.app.ActivityThread"
zygoteWriter.write(msgStr);
//刷數(shù)據(jù),全部寫入Zygote進(jìn)程,處于阻塞狀態(tài)
zygoteWriter.flush();
//從socket中得到zygote創(chuàng)建的應(yīng)用pid,賦值給 ProcessStartResult的對象
Process.ProcessStartResult result = new Process.ProcessStartResult();
//從socket中讀取創(chuàng)建的進(jìn)程的pid
result.pid = zygoteInputStream.readInt();
result.usingWrapper = zygoteInputStream.readBoolean();
//如果pid<0,表示創(chuàng)建失敗
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
return result;
}
...
}
最后會通過socket連接到Zygote進(jìn)程,將對應(yīng)的參數(shù)發(fā)送給Socket的Server端以后,由Server端來進(jìn)行進(jìn)程的fork操作,操作完成以后將創(chuàng)建的進(jìn)程id返回。
那么Zygote的Server端又是如何創(chuàng)建的呢?
Zygote啟動監(jiān)聽
這個就涉及了Zygote的啟動過程了。這部分我們后續(xù)可以詳細(xì)分析,這里只提一下大體的流程。
Zygote會先fork出SystemServer進(jìn)程,然后會進(jìn)入循環(huán)等待,用來接收Socket發(fā)來的消息,用來fork出其他應(yīng)用所需要的進(jìn)程信息。
//ZygoteInit.java
public static void main(String argv[]) {
ZygoteServer zygoteServer = null;
Runnable caller;
try {
//創(chuàng)建一個ZygoteServer對象,這個對象創(chuàng)建一個socket服務(wù)端,能夠接收連接并且孵化對應(yīng)的子進(jìn)程
zygoteServer = new ZygoteServer(isPrimaryZygote);
if (startSystemServer) {
//Fork出第一個進(jìn)程 SystemServer服務(wù)所需的進(jìn)程
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
if (r != null) {
//啟動SystemServer服務(wù)
r.run();
return;
}
}
//***重點方法*** 這里會進(jìn)入循環(huán)等待,用來接收Socket發(fā)來的消息,用來fork出其他應(yīng)用所需要的進(jìn)程信息。并且返回fork出的進(jìn)程的啟動函數(shù)
caller = zygoteServer.runSelectLoop(abiList);
....
if (caller != null) {
//調(diào)用caller的run方法,啟動子進(jìn)程(run方法會調(diào)用子進(jìn)程的啟動程序的main方法,也就是ActivityThread.java的main()方法)
caller.run();
}
}
連接的處理
我們這里看一下runSelectLoop這個方法如何監(jiān)聽Socket連接以及接收消息的
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> socketFDs = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
//socketFDs[0]是socketServer。
socketFDs.add(mZygoteSocket.getFileDescriptor());
peers.add(null);
//死循環(huán)
while (true) {
{
//這里會進(jìn)入阻塞,當(dāng)有pollFDs事件到來的時候,則繼續(xù)往下執(zhí)行
Os.poll(pollFDs, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
while (--pollIndex >= 0) {
if (pollIndex == 0) {
//采用I/O 多路復(fù)用機制,index==0表示selcet接收到的是Zygote的socket連接的事件.
// 客戶端第一次請求服務(wù)端,服務(wù)端會調(diào)用accept方法與客戶端建立連接,客戶端在zygote以ZygoteConnection對象表示
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
socketFDs.add(newPeer.getFileDescriptor());
} else if (pollIndex < usapPoolEventFDIndex) {
//當(dāng)連接以后,能夠接收指令,這里根據(jù)
try {
//peers.get(index)取得發(fā)送數(shù)據(jù)客戶端的ZygoteConnection對象。這個就是多路復(fù)用的機制了
ZygoteConnection connection = peers.get(pollIndex);
//收到Socket發(fā)來的消息,進(jìn)行fork的創(chuàng)建工作。返回的command是MethodAndArgsCaller類
//其run方法,會調(diào)用通過socket接收到的啟動類的main方法
final Runnable command = connection.processOneCommand(this);
....
}
當(dāng)啟動循環(huán)以后,會一直遍歷等待,等待接收Socket發(fā)來的連接以及消息請求。當(dāng)獲取到對應(yīng)的客戶端的ZygoteConnection對象以后,這里會調(diào)用processOneCommand指令來進(jìn)行處理。
到這里的話,就可以和我們剛才講的創(chuàng)建Socket連接關(guān)聯(lián)起來了。
我們看一下processOneCommand這個方法是如何對發(fā)送的相關(guān)fork進(jìn)程的參數(shù)來進(jìn)行處理的。
Runnable processOneCommand(ZygoteServer zygoteServer) {
String args[];
ZygoteArguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
//讀取socket傳來的參數(shù)信息
args = Zygote.readArgumentList(mSocketReader);
...
parsedArgs = new ZygoteArguments(args);
fd = null;
//*****重點方法**** fork一個子進(jìn)程,得到一個對應(yīng)的進(jìn)程pid
pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mTargetSdkVersion);
try {
if (pid == 0) {
//當(dāng)pid=0,說明是fork的子進(jìn)程
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
//****重點方法***** 處理子進(jìn)程
return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.mStartChildZygote);
...
}
我們將這個方法分為3個大內(nèi)容來處理
- 將接收到的數(shù)據(jù)進(jìn)行解析處理,生成ZygoteArguments對象,這個對象里面包含了我們設(shè)置的進(jìn)程創(chuàng)建以后的入口類(即啟動類)
- 通過forkAndSpecialize方法fork出一個子進(jìn)程
- 通過handleChildProc方法對fork出的子進(jìn)程進(jìn)行處理
我們分別對上面的3部分進(jìn)行分析:
參數(shù)的解析
這里接收的參數(shù),是在我們的socket的client端來進(jìn)行創(chuàng)建的。
//ZygoteProcess.java #startViaZygote方法
ArrayList<String> argsForZygote = new ArrayList<>();
// --runtime-args, --setuid=, --setgid=,
// and --setgroups= must go first
//這是一些創(chuàng)建進(jìn)程時候的參數(shù)信息
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");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {
argsForZygote.add("--mount-external-full");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
argsForZygote.add("--mount-external-installer");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_LEGACY) {
argsForZygote.add("--mount-external-legacy");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
argsForZygote.add(processClass);
//ZygoteProcess.java # zygoteSendArgsAndGetResult方法
String msgStr = args.size() + "\n" + String.join("\n", args) + "\n";
這里的參數(shù)的樣式是"--setuid=1",行與行之間以"\r"、"\n"或者"\r\n"分割,最后一個參數(shù)是進(jìn)程的入口類。在解析的時候,會按照格式進(jìn)行拆分。
子進(jìn)程的創(chuàng)建
對于子進(jìn)程的fork,是通過Zygote.forkAndSpecialize來處理的。
//Zygote.java
//fork一個子進(jìn)程,如果這是子節(jié)點則返回0;如果這是父進(jìn)程,則返回子進(jìn)程的pid;發(fā)生異常則返回-1。
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,
int targetSdkVersion) {
...
//調(diào)用native方法,fork出一個子進(jìn)程。具體的位置在com_android_internal_os_Zygote.cpp
int pid = nativeForkAndSpecialize(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,fdsToIgnore, startChildZygote, instructionSet, appDataDir);
...
return pid;
}
這里調(diào)用了一個native方法來進(jìn)行線程的fork操作。由于采用copy on write方式,這里執(zhí)行一次,會返回兩次。
創(chuàng)建結(jié)果的處理
當(dāng)通過native進(jìn)行了子進(jìn)程的fork操作以后,會返回pid。這里的pid根據(jù)具體的值表示的是不同的類型
- pid=0:表示處于子進(jìn)程
- pid>0:表示處于Zygote進(jìn)程
- pid<0:表示子進(jìn)程的創(chuàng)建失敗
這里我們只關(guān)心子進(jìn)程的處理。也就是handleChildProc方法。
//ZygoteConnection.java
//進(jìn)程創(chuàng)建完成后的處理工作,適當(dāng)?shù)年P(guān)閉socket,適當(dāng)?shù)闹匦麓蜷_stdio,返回成功或者失敗信息等
//返回的Runnable是一個封裝了創(chuàng)建進(jìn)程時,socket傳進(jìn)來的程序入口的方法以及對應(yīng)的參數(shù)的類。其run方法會通過反射調(diào)用類的main方法
private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors,FileDescriptor pipeFd, boolean isZygote) {
//當(dāng)執(zhí)行到這的時候,connection已經(jīng)關(guān)閉了關(guān)閉socket,用/dev/null替換它們。
closeSocket();
...
//這個里面會通過反射創(chuàng)建socket傳遞的啟動程序的入口類(ActivityThread),然后調(diào)用其main方法進(jìn)行啟動
return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mRemainingArgs, null /* classLoader */);
}
}
}
這個方法在最后會調(diào)用childZygoteInit方法,然后返回一個Runnable對象。
static final Runnable childZygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
//根據(jù)argv獲取到對應(yīng)的運行的相關(guān)參數(shù)
RuntimeInit.Arguments args = new RuntimeInit.Arguments(argv);
return RuntimeInit.findStaticMain(args.startClass, args.startArgs, classLoader);
}
這里根據(jù)解析后的參數(shù)信息,生成了Arguments對象。
//RuntimeInit.java
Arguments(String args[]) throws IllegalArgumentException {
parseArgs(args);
}
//進(jìn)行參數(shù)的解析
private void parseArgs(String args[]) throws IllegalArgumentException {
int curArg = 0;
for (; curArg < args.length; curArg++) {
String arg = args[curArg];
if (arg.equals("--")) {
curArg++;
break;
} else if (!arg.startsWith("--")) {
break;
}
}
//在傳遞參數(shù)的時候,最后一項傳遞的是程序入口類的信息
startClass = args[curArg++];
//參數(shù)信息
startArgs = new String[args.length - curArg];
System.arraycopy(args, curArg, startArgs, 0, startArgs.length);
}
}
方法中會根據(jù)傳入的參數(shù)確定了fork的子進(jìn)程啟動時的類startClass以及對應(yīng)的參數(shù)startArgs。
//ZygoteInit.java
//調(diào)用傳入的className所對應(yīng)的類的main方法
protected static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) {
Class<?> cl;
//反射創(chuàng)建類
cl = Class.forName(className, true, classLoader);
Method m;
//獲取類的main方法
m = cl.getMethod("main", new Class[] { String[].class });
//封裝一個Runnable類,將方法和參數(shù)都傳遞給了該類,其run方法會通過反射調(diào)用main方法
return new MethodAndArgsCaller(m, argv);
}
static class MethodAndArgsCaller implements Runnable {
//調(diào)用的方法
private final Method mMethod;
//方法的參數(shù)
private final String[] mArgs;
public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}
public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
}
...
}
}
handleChildProc會根據(jù)將傳入的參數(shù)信息,返回子進(jìn)程啟動時所使用的方法通過反射獲取到,并放在一個Runnable的run方法中去執(zhí)行。
那么這個Runnable的啟動是在哪兒呢?
//ZygoteInit.java
public static void main(String argv[]) {
...
caller = zygoteServer.runSelectLoop(abiList);
...
if (caller != null) {
//調(diào)用caller的run方法,啟動子進(jìn)程(run方法會調(diào)用子進(jìn)程的啟動程序的main方法,也就是ActivityThread.java的main()方法)
caller.run();
}
當(dāng)通過runSelectLoop方法fork完對應(yīng)的子進(jìn)程以后,會將這個MethodAndArgsCaller返回并執(zhí)行。我們一開始傳入的ActivityThread的main方法就調(diào)用并執(zhí)行了。
總結(jié)
- 在fork子進(jìn)程之后,直接執(zhí)行了ActivityThread的main方法來啟動的。
- 在系統(tǒng)啟動時,開啟了Zygote的Socket的Server端來監(jiān)聽,當(dāng)需要創(chuàng)建進(jìn)程時,直接通過Socket連接,然后傳遞參數(shù)來創(chuàng)建。
- fork采用了copy on write方式。
- Server端對于連接的處理,采用了I/O 多路復(fù)用機制。具體的這個機制,這個機制回頭可以延伸一下。
本文由 開了肯 發(fā)布!
同步公眾號[開了肯]