應用程序的進程啓動java
當咱們打開android手機的時候,不知道你是否想過app是如何啓動的呢?android
接下來,我將從源碼角度進行解析,固然,本文做爲上篇,是介紹應用程序的進程啓動過程,而不是應用程序的啓動過程,他們的區別就是煮飯前要準備鍋具,沒有鍋具就沒法煮飯,本文就是準備鍋具的,可是也不簡單哦。c++
文章將從兩個方面介紹,一個AMS發送請求,一個是Zygote接受請求。web
AMS就是Activity Manager System,管理Activity的,而Zygote就是建立進程的一個進程,因此AMS要想建立進程必須從Zygote那裏進行申請,一系列的故事,就此展開。微信
從圖中能夠簡略看出,首先AMS本身調用了本身的startProcessLocked
方法,會建立相應的用戶id,用戶id組,以及對應的應用程序進程的主線程名——android.app.ActivityThread
。app
private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
...
try {
int uid = app.uid;
int[] gids = null;
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
if (!app.isolated) {
int[] permGids = null;
if (ArrayUtils.isEmpty(permGids)) {
gids = new int[3];
} else {
gids = new int[permGids.length + 3];
System.arraycopy(permGids, 0, gids, 3, permGids.length);
}
gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));
}
String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
if (requiredAbi == null) {
requiredAbi = Build.SUPPORTED_ABIS[0];
}
...
if (entryPoint == null) entryPoint = "android.app.ActivitThread";
...
if (hostingType.equals("webview_service")) {
...
} else {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, entryPointArgs);
}
...
}
複製代碼
這裏面的start中有一個參數名爲requireAbi
,在下面會改爲abi
起到比對的重要做用。socket
startProcessLocked
方法內部會調用Process的start
方法,而這個start方法只幹了一件事,就是調用ZygoteProcess
的start
方法。ide
ZygoteProcess
的做用在於保持與Zygote通訊的狀態,在其start
方法中,會調用StartViaZygote
方法,這裏的出現了下面很重要的abi。函數
public final Process.ProcessStartResult start(final String processClass, final String niceName, int uid, int gid, int[] gids, ... String abi, ... String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
...
}
複製代碼
StartViaZygote
方法會維護一個名爲argsForZygote
的列表,顧名思義,全部可以啓動應用程序的進程的參數,都會保存在這裏。而後這個列表做爲一個參數,被傳入到ZygoteSendArgsAndGetResult
方法中,這個方法也是在StartViaZygote
方法中被調用.另外要注意的是,openZygoteSocketIfNeeded
方法也是做爲參數傳入了ZygoteSendArgsAndGetResult
方法中。oop
private Process.ProcessStartResult startViaZygote(final String processClass, final String niceName, final int uid, final int gid, final int[] gids, ... String abi, ...) throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<String>();
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
...
synchronized(mLock) {
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
複製代碼
ZygoteSendArgsAndGetResult
方法做用是將傳入的參數,也就是argsForZygote
中保存的數據寫入到ZygoteState
中,從圖中咱們雖然將ZygoteState
和ZygoteProcess
作了並列處理,可是ZygoteState
是ZygoteProcess
的一個靜態內部類,上面提到的ZygoteProcess
的做用在於保持與Zygote通訊的狀態,其功能的完成就是在ZygoteState
中。
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();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
writer.write(arg);
writer.newLine();
}
writer.flush();
...
result.pid = inputStream.readInt();
result.usingWrapper = inputStream.readBoolean();
...
}
複製代碼
從上面的方法看出,ZygoteSendArgsAndGetResult
方法的第一個參數變成了ZygoteState
,也就是說,openZygoteSocketIfNeeded
方法的返回值是ZygoteState
。
openZygoteSocketIfNeeded
方法也處於ZygoteProcess
中,就寫在StartViaZygote
下面,能夠看到,在第6行與Zygote進程創建了鏈接。
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedE Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
primaryZygoteState = ZygoteState.connect(mSocket);//創建鏈接
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
}
//這裏primaryZygoteState是鏈接主模式後返回的ZygoteState,比對其是否與須要的abi匹配
if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}
//若是主模式不成功,鏈接輔模式
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
try {
secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
}
}
//匹配輔模式的abi
if (secondaryZygoteState.matches(abi)) {
return secondaryZygoteState;
}
throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
複製代碼
爲何第6行能夠鏈接Zygote呢?由於Zygote是最早建立的進程,若是沒有Zygote,咱們的應用程序的進程也無從談起,而Zygote爲了建立其餘進程,他會設置一個Socket監聽,就是經過這個Socket,完成與Zygote的鏈接。
而對於主模式和輔助模式,這裏不細講,就是有兩次鏈接並匹配abi
的機會。
要匹配abi
的緣由在於,Zygote雖然能夠fork本身不斷建立進程,可是畢竟是有限的,並且須要資源,只有啓動某個應用程序所必須的進程纔有被建立的意義,這時候就在一開始的AMS中給設置一個abi
,若是與後來的Zygote匹配,證實是須要被建立的。
當匹配完成時,就會返回一個primaryZygoteState
,此時AMS發送請求這一流程就結束了,接下來,就是Zygote如何接受請求並建立應用程序的進程的過程了。
依然是時序圖,甚至說,有了時序圖,根本就不須要看後面的文章啦。
看起來比上一個圖稍微複雜些,不過能夠發現仍是頗有規律的,Zygote先到ZygoteServer
再回來,再到ZygoteConnection
,再回來……
因此,後面幾個方法都在ZygoteInit
中被調用,並且時間前後就是圖中所示。
在AMS發送請求完成後,Zygote會鏈接到一個ZygoteState
,而這個ZygoteState
在以前的ZygoteSendArgsAndGetResult
方法中被寫入了argsForZygote
所保存的數據,這些數據就是請求的具體參數。
如今Zygote將會收到這些參數,並在ZygoteInit
中進行相應操做。
ZygoteInit
首先會執行其main方法。
public static void main(String argv[]) {
...
try {
...
//設置Socket監聽
zygoteServer.registerServerSocket(socketName);
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();
...
if (startSystemServer) {
startSystemServer(abiList, socketName, zygoteServer);//啓動SystemServer進程
}
Log.i(TAG, "Accepting command socket connections");
zygoteServer.runSelectLoop(abiList);//等待AMS請求
zygoteServer.closeServerSocket();
...
}
複製代碼
這裏最後一個註釋,就是一切都準備好了,只等AMS發來請求,如今咱們看看RunSelectLoop
方法是如何作的,猜想既然是等待,那確定有一個死循環while,這個函數就在ZygoteServer
之中。
void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
while (true) {
...
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 {
//一個鏈接一個鏈接的運行
boolean done = peers.get(i).runOnce(this);
if (done) {
peers.remove(i);
fds.remove(i);
}
}
}
}
}
複製代碼
果真有一個while(true),哈哈,獎勵本身晚上早睡十分鐘。
能夠看到這裏維護了一個ZygoteConnection
型的列表,每當鏈接不夠時,就會增長,而後一個一個鏈接的進行執行,執行玩一個鏈接,就移除一個。
runOnce
方法的做用就是讀取argsForZygote
所保存的數據,完成交接,這個方法顯然,在ZygoteConnection
中。
boolean runOnce(ZygoteServer zygoteServer) throws Zygote.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;
}
...
try {
parsedArgs = new Arguments(args);
...
//建立應用程序進程
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) {//當前邏輯運行在子程序中
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
return true;
}
...
}
}
複製代碼
若是在18行處的pid返回值爲0,那麼恭喜,此時的子進程已經建立完成,各類id和參數都傳進去了,此時就會調用handleChildProc
方法來處理出現的應用程序的進程(仍是要提醒,本文建立的是應用程序的進程,而非應用程序自己)。
handleChildProc
方法回調了ZygoteInit
中的zygoteInit
方法,注意,這裏的z是小寫!
private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr) throws Zygote.MethodAndArgsCaller {
...
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 {
ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
複製代碼
如今咱們回到ZygoteInit
中,看看zygoteInit
是怎麼寫的。
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();
RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
複製代碼
注意到這個方法是一個靜態的final方法,在12行代碼處,會執行RuntimeInit
的applicationInit
方法。
protected static void applicationInit(int targetSdkVersion, String[] throws Zygote.MethodAndArgsCaller { ... final Arguments args; try { args = new Arguments(argv);
} catch (IllegalArgumentException ex) {
Slog.e(TAG, ex.getMessage());
// let the process exit
return;
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
invokeStaticMain(args.startClass, args.startArgs, classLoader);
}
複製代碼
一樣在最後一行,調用了invokeStaticMain
方法,這裏傳入了三個參數,第一個參數args.startClass
就是本文一開始說的那個主線程的名字android.app.MainThread
。
終於咱們到了最後一站!如今咱們進入invokeStaticMain
方法。
private static void invokeStaticMain(String className, String[] argv, ClassLoader throws Zygote.MethodAndArgsCaller { Class<?> cl; try { cl = Class.forName(className, true, classLoader);//反射獲取MainThread
} 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
} 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);
...
throw new Zygote.MethodAndArgsCaller(m, argv);
}
複製代碼
這裏的className就是咱們剛剛提到的args.startClass
,也就是主線程名字,經過第6行的反射獲取到對應的類,命名爲c1,而後再經過15行代碼獲取主方法main,並將main傳入到MethodAndArgsCaller
方法中,當作異常拋出。
爲何這裏要用拋出異常的方法呢?
聯想到這是最後一步,拋出異常的方式將會清除設置過程當中須要的堆棧幀,僅僅留下一個main方法,使得main方法看起來像一個入口方法,畢竟,前面那麼多的工做,那麼多類的流血犧牲,最後都是爲了成就他。當他出現時,前面的東西,也就沒有必要存在了。
如今異常拋出了,誰來接受呢?固然,是main了,main位於ZygoteInit
中。
public static void main(String argv[]) {
...
zygoteServer.closeServerSocket();
} catch (Zygote.MethodAndArgsCaller caller) {
caller.run();
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
zygoteServer.closeServerSocket();
throw ex;
}
}
複製代碼
能夠看到,當出現了一個MethodAndArgsCaller
型的異常的時候,main會捕捉到,而且執行他的run方法,這個run方法在MethodAndArgsCaller
中,他是一個靜態類。
public static class MethodAndArgsCaller extends Exception implements Runnable {
...
public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
...
}
}
}
複製代碼
調用了invoke
方法後,ActivityThread裏面的main方法就會被動態調用,應用程序的進程就進入了這一main方法中。
通過上面的種種操做,咱們建立了應用程序的進程而且運行了ActivityThread。
簡單來講就是要想建立應用程序的進程,須要AMS發送請求,傳入主線程名,這一請求必須符合Zygote的abi
,而且將請求參數寫在ZygoteState
中。
而後Zygote讀取參數,fork自身去生成新的進程,若是返回的pid爲0,那麼就完成了應用程序的進程的建立。
而後經過反射將主線程名轉換爲主線程的類,得到其main方法,經過拋出一個異常清除掉以前的堆棧幀,在main方法裏面接受這個異常,並執行run方法以激活main方法,使得應用程序的進程進入到main方法中得以運行。
寫了一早上,呼~,準備吃飯啦,還有什麼不懂的能夠評論區提問哦。
本文取材自《Android進階解密》,資源在微信公衆號【小松漫步】,一塊兒交流學習吧。