我們都知道Android系統是架構在linux內核之上移動操作系統。在unix系統中所有的進程都是在init進程的子進程,有init進程負責fork創建。所以zygote進程肯定也是init進程fork出來的子進程。關於init進程的啓動暫時不談。
那麼Zygote進程作爲android 應用程序進程和系統服務進程SystemServer的主進程,那我主要做了哪些工作呢?我們通過源碼分析一下。
這片文章我們只要分析Zygote進程的啓動流程來加深一下了解。init進程在啓動Zygote進程時一般都會調用ZygoteInit類的main方法,那麼我們看一下main方法的具體實現(android23源碼)。
main()方法內容:
public class ZygoteInit { public static void main(String argv[]) { try { //1.在此主要完成了ddms的啓動, RuntimeInit.enableDdms(); // Start profiling the zygote initialization. //2.開始分析zygote進程的初始化 SamplingProfilerIntegration.start(); boolean startSystemServer = false; String socketName = "zygote"; String abiList = null; for (int i = 1; i < argv.length; i++) { if ("start-system-server".equals(argv[i])) { startSystemServer = 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."); } //3.zygote進程註冊socket registerZygoteSocket(socketName); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); //4.資源預加載 preload(); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); // Finish profiling the zygote initialization. //5.結束對zygote進程初始化的分析 SamplingProfilerIntegration.writeZygoteSnapshot(); // Do an initial gc to clean up after startup gcAndFinalize(); // Disable tracing so that forked processes do not inherit stale tracing tags from // Zygote. Trace.setTracingEnabled(false); if (startSystemServer) { //6.啓動systemserver startSystemServer(abiList, socketName); } Log.i(TAG, "Accepting command socket connections"); //7.接受進程請求 runSelectLoop(abiList); //8.關閉socket closeServerSocket(); } catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket(); throw ex; } } }
我們總結一下真個main方法都完成了哪些事情:
- 啓動android DDMS.
- 開始分析zygote進程的初始化,本方法主要是結合VM相關機制.
- zygote進程註冊於系統通信的socket。
- 資源的預加載 主要加載了:通用class,資源,opengl,共享庫, 字符資源,以及webview的初始化準備。
- 啓動systemserver. systemserver負責很多android重要服務的管理,如:packageManagerService ,ActivityManagerService等。具體SystemServer都做了哪些工作以後在好好看看。
- 處理客戶端的連接和請求。
- 關閉socket連接。
registerZygoteSocket()源碼如下:
/**
* Registers a server socket for zygote command connections
* 註冊一個zygote進程的連接socket
*
* @throws RuntimeException when open fails
*/
private static void registerZygoteSocket(String socketName) {
if (sServerSocket == null) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
sServerSocket = new LocalServerSocket(fd);
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
從環境變量中獲得名爲“ANDROID_SOCKET_zygote”的值作爲socket的fd。zygote進程的文件就是/dev/socket/zygote文件。
ANDROID_SOCKET_zygote就是進程文件的fd。其中註冊zygote的socket就是調用了native層的相關方法在此暫時不談。
preload()方法的內容下:
static void preload() {
Log.d(TAG, "begin preload");
preloadClasses();
preloadResources();
preloadOpenGL();
preloadSharedLibraries();
preloadTextResources();
// Ask the WebViewFactory to do any initialization that must run in the zygote process,
// for memory sharing purposes.
WebViewFactory.prepareWebViewInZygote();
Log.d(TAG, "end preload");
}
類和資源的預先加載都比較簡單就不多說了。注意到webview在zygote進程中準備了一些初始化的工作,主要是爲native層的庫配置內存地址空間。
啓動systemserver:
/**
* Prepare the arguments and fork for the system server process.
*/
private static boolean startSystemServer()
throws MethodAndArgsCaller, RuntimeException {
long capabilities = posixCapabilitiesAsBits(
OsConstants.CAP_KILL,
OsConstants.CAP_NET_ADMIN,
OsConstants.CAP_NET_BIND_SERVICE,
OsConstants.CAP_NET_BROADCAST,
OsConstants.CAP_NET_RAW,
OsConstants.CAP_SYS_MODULE,
OsConstants.CAP_SYS_NICE,
OsConstants.CAP_SYS_RESOURCE,
OsConstants.CAP_SYS_TIME,
OsConstants.CAP_SYS_TTY_CONFIG
);
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000", // #define AID_SYSTEM 1000
"--setgid=1000", // 1000 是系統屬性
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
"--capabilities=" + capabilities + "," + capabilities,
"--runtime-init",
"--nice-name=system_server", // 進程名爲system_server
"com.android.server.SystemServer", // 類名
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
/*
進程啓動參數都已經在上面硬編碼了
最後調用fork啓動system_server進程
*/
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
if (pid == 0) {
// 子進程處理消息
handleSystemServerProcess(parsedArgs);
}
return true;
}
runSelectLoop()方法等待請求:
private static void runSelectLoop() throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
FileDescriptor[] fdArray = new FileDescriptor[4];
//記錄sServerSocket的fd信息
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
int loopCount = GC_LOOP_COUNT;
while (true) {
int index;
/*
* Call gc() before we block in select().
* It's work that has to be done anyway, and it's better
* to avoid making every child do it. It will also
* madvise() any free memory as a side-effect.
*
* Don't call it every time, because walking the entire
* heap is a lot of overhead to free a few hundred bytes.
*/
if (loopCount <= 0) {
gc();
loopCount = GC_LOOP_COUNT;
} else {
loopCount--;
}
try {
fdArray = fds.toArray(fdArray);
//selectReadable是一個native函數
index = selectReadable(fdArray);
} catch (IOException ex) {
throw new RuntimeException("Error in select()", ex);
}
if (index < 0) {
throw new RuntimeException("Error in select()");
} else if (index == 0) {
ZygoteConnection newPeer = acceptCommandPeer();
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
boolean done;
done = peers.get(index).runOnce();
// 請求處理完成之後,移除與該客戶端的連接
if (done) {
peers.remove(index);
fds.remove(index);
}
}
}
}
selectReadable()方法是個native方法,內部是調用了unix的select()來建立socket連接。當外部請求socket連接時會返回一個值。
返回值代表的意思如下:
小於0: 內部發生錯誤
等於0: 該客戶端第一次連接到服務端
大於0: 客戶端與服務端已經建立連接,並開始發送數據
於是就有了下面判斷的各種處理。