我们都知道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方法都完成了哪些事情:
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 fds = new ArrayList();
ArrayList peers = new ArrayList();
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: 客户端与服务端已经建立连接,并开始发送数据
于是就有了下面判断的各种处理。