在上篇文章Android點擊Launcher應(yīng)用圖標(biāo)的應(yīng)用程序啟動過程(棧和進(jìn)程的創(chuàng)建)中我們分析了在Home中點擊應(yīng)用圖標(biāo)后的啟動過程及棧和進(jìn)程的創(chuàng)建過程雷则。我們講到了AMS通過socket通信到了Zygote,那么下面我們繼續(xù)看下Zygote是如何處理客戶端請求的。
處理客戶端請求
在ZygoteInit的main函數(shù)中通過zygoteServer.runSelectLoop(abiList)來接收客戶端請求的:
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
while (true) {//無限循環(huán)
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;
}
...
if (i == 0) {//index==0表示selcet接收到的是Zygote的socket的事件
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
try {
ZygoteConnection connection = peers.get(i);
//調(diào)用ZygoteConnection對象的processOneCommand方法聂使,ZygoteConnection是在index == 0時被添加到peers的
final Runnable command = connection.processOneCommand(this);
...
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(i);
fds.remove(i);
}
}
}
}...
}
}
每當(dāng)有請求過來時,Zygote都會調(diào)用ZygoteConnection的processOneCommand()方法處理:
Runnable processOneCommand(ZygoteServer zygoteServer) {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
//讀取客戶端發(fā)送過來的參數(shù)
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
throw new IllegalStateException("IOException on command socket", ex);
}
...//省略一系列操作步驟
//fork一個新進(jìn)程
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) {//子進(jìn)程
// in child
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.startChildZygote);
} else {//父進(jìn)程
// 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);
}
}
Zygote在處理客戶端請求時會fork一個新的進(jìn)程,接下來首先看一下handleChildProc()方法:
/Volumes/android/WORKING_DIRECTORY/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd, boolean isZygote) {
closeSocket();//關(guān)閉子進(jìn)程理郑,從Zygote fork過來的服務(wù)端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);
}
} 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) {//沒有傳入--invoke-with肴甸,所以這里走的是else
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) { //如果是啟動一個Zygite的子Zygote線程寂殉,這里為false所以走else
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
null /* classLoader */);
} else {
return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
}
這里調(diào)用ZygoteInit的zygoteInit()方法:
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");
//指定系統(tǒng)log輸出到andorid
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit();//初始化系統(tǒng)屬性
ZygoteInit.nativeZygoteInit();
////應(yīng)用初始化
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
這里注釋已經(jīng)說的很清楚了我們來看一下這幾個方法的實現(xiàn)
- RuntimeInit.redirectLogStreams():
public static void redirectLogStreams() {
System.out.close();
System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));
System.err.close();
System.setErr(new AndroidPrintStream(Log.WARN, "System.err"));
}
這里將System.out 和 System.err 輸出重定向到Android 的Log系統(tǒng)。
- RuntimeInit.commonInit():
protected static final void commonInit() {
if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
LoggingHandler loggingHandler = new LoggingHandler();
RuntimeHooks.setUncaughtExceptionPreHandler(loggingHandler);
Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));
RuntimeHooks.setTimeZoneIdSupplier(() -> SystemProperties.get("persist.sys.timezone"));
LogManager.getLogManager().reset();
new AndroidConfig();
String userAgent = getDefaultUserAgent();
System.setProperty("http.agent", userAgent);
NetworkManagementSocketTagger.install();
String trace = SystemProperties.get("ro.kernel.android.tracing");
if (trace.equals("1")) {
Slog.i(TAG, "NOTE: emulator trace profiling enabled");
Debug.enableEmulatorTraceOutput();
}
initialized = true;
}
初始化了一些系統(tǒng)屬性原在,其中最重要的一點就是設(shè)置了一個未捕捉異常的handler友扰,當(dāng)代碼有任何未知異常,就會執(zhí)行它庶柿, 調(diào)試過Android代碼的同學(xué)經(jīng)炒骞郑看到的"*** FATAL EXCEPTION IN SYSTEM PROCESS" 打印就出自這里的LoggingHandler對象。
- ZygoteInit.nativeZygoteInit():
該方法是一個本地方法浮庐, 最終會調(diào)用app_main的onZygoteInit函數(shù) 這里的作用是在新進(jìn)程中引入Binder甚负,也就說通過nativeZygoteInit以后,新的進(jìn)程就可以使用Binder進(jìn)程通信了审残。 - RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader):
protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {
// 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 = 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);
}
在applicationInit()的最后腊敲,會通過調(diào)用findStaticMain來調(diào)用args.startClass這個類的main()方法。在前面介紹socket的客戶端代碼時维苔,在startProcessLocked()中傳入的這個類為"android.app.ActivityThread"碰辅。所以接下來findStaticMain()的功能相信大家都已經(jīng)知道了,就是調(diào)用ActivityThread類的main()介时,下面是代碼:
protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader) {
Class<?> cl;
try {
cl = Class.forName(className, true, classLoader);
} 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 });
} 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.
*/
return new MethodAndArgsCaller(m, argv);
}
這個方法本身功能就是調(diào)用ActivityThread類的main()没宾,沒什么可說的。這里痛class獲取ActivityThreadActivityThread類的main()方法封裝在new MethodAndArgsCaller中并返回到ZygoteInit.main()中(老的版本統(tǒng)統(tǒng)一個奇怪的方式:拋出ZygoteInit.MethodAndArgsCaller異常會在ZygoteInit.main()中被捕獲處理):
public static void main(String argv[]) {
...
// We're in the child process and have exited the select loop. Proceed to execute the
// command.
if (caller != null) {
caller.run();
}
}
這里的caller是com.android.internal.os.RuntimeInit.MethodAndArgsCaller沸柔,它實現(xiàn)了Runnable接口循衰,這里調(diào)用器run方法。這里需要注意的是:cller.run在子進(jìn)程(即新的進(jìn)程褐澎,不是Zygote進(jìn)程)中的動作会钝。還記得前面介紹的processOneCommand()方法嗎?我們在processOneCommand中創(chuàng)建了一個新的進(jìn)程工三。如果讀者還有不明白這里為什么是在子進(jìn)程迁酸,可以自行學(xué)習(xí)Linux fork()的原理。那么我們繼續(xù)看下它的run方法里做了什么:
public void run() {
try {
mMethod.invoke(null, new Object[] { 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);
}
}
這里 看到了mMethod.invoke(null, new Object[] { mArgs })俭正,原來最后還是會調(diào)用invoke方法通過反射的方式調(diào)用ActivityThread的main方法奸鬓。
到了這里,相信大家都會有一個疑問:既然最后還是通過invoke來反射調(diào)用main方法掸读,那繞這一大圈子到底在折騰什么串远?
有疑問的讀者宏多,有沒有去思考過另外一個問題:我們?yōu)槭裁匆ㄟ^Zygote去創(chuàng)建進(jìn)程,而不是直接創(chuàng)建一個新的進(jìn)程出來呢澡罚?這就要從Zygote創(chuàng)建進(jìn)程的機(jī)制來解釋伸但。相信我們還記得在ZygoteInit的main函數(shù)中我們通過preload來預(yù)加載類和資源。所以這些被預(yù)加載的類和資源都存在于Zygote進(jìn)程中留搔。在通過Zygote創(chuàng)建進(jìn)程時更胖,我們是通過fork來創(chuàng)建的。 一個進(jìn)程調(diào)用fork()函數(shù)后催式,系統(tǒng)先給新的進(jìn)程分配資源,例如存儲數(shù)據(jù)和代碼的空間避归。然后把原來的進(jìn)程的所有值都復(fù)制到新的新進(jìn)程中荣月,只有少數(shù)值與原來的進(jìn)程的值不同,相當(dāng)于克隆了一個自己梳毙。所以哺窄,Zygote通過fork的方式創(chuàng)建新的應(yīng)用進(jìn)程的同時,會將對系統(tǒng)的(主要是framework中的)一些類和資源的引用同時復(fù)制給子進(jìn)程账锹,這樣子進(jìn)程中就可以使用這些資源了萌业。這也是為什么所有的應(yīng)用程序可以共享Framework中的類和資源的原因。
好了到這里就已經(jīng)創(chuàng)建好新的應(yīng)用進(jìn)程了奸柬,接下來就是應(yīng)用的初始化過程了生年,下篇文章再見了!