Android Zygote启动流程源码解析
Posted 一口仨馍
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Zygote启动流程源码解析相关的知识,希望对你有一定的参考价值。
本文已授权微信公众号《鸿洋》原创首发,转载请务必注明出处。
Zygote
进程是android
和Java
世界的开创者。在Android
系统中,所有的应用进程和SystemServer
进程都是由Zygote
进程fork
而来。其重要性由此可见一斑。虽然Zygote
进程相当于Android
系统的根进程,但是事实上它也是由Linux
系统的init
进程启动的。各个进程的先后顺序为:
init
进程 –-> Zygote
进程 –> SystemServer
进程 –>应用进程
其中Zygote
进程由init
进程启动,SystemServer
进程和应用进程由Zygote
进程启动。本文依据6.0源码,主要分析Zygote
进程的启动流程。init
进程在启动Zygote
进程时会调用ZygoteInit#main()
。以此为切入点,一步步分析。
源码位置:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
流程概览
ZygoteInit#main();
public static void main(String argv[])
try
// 设置DDMS可用
RuntimeInit.enableDdms();
// 初始化启动参数
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]);
// 注册socket
registerZygoteSocket(socketName);
// 预加载各种资源
preload();
...
if (startSystemServer)
// 启动SystemServer进程
startSystemServer(abiList, socketName);
// 监听socket,启动新的应用进程。--后文会讲
runSelectLoop(abiList);
closeServerSocket();
catch (MethodAndArgsCaller caller)
// 通过反射调用SystemServer#main()--后文会讲
caller.run();
catch (RuntimeException ex)
closeServerSocket();
throw ex;
上面是个大概流程,下面会依据源码一步步解释。设置DDMS
可用之后初始化各种参数,在此之后注册为Zygote
进程注册Socket
,预加载各种资源,但这些都不是重点!同学们,重点在于startSystemServer(abiList, socketName)
(手敲黑板状)!下面简单贴下registerZygoteSocket(socketName)
和preload()
源码,不感兴趣的同学可直接略过下面两段代码。
ZygoteInit#registerZygoteSocket()
private static void registerZygoteSocket(String socketName)
if (sServerSocket == null)
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
...
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
// 不是使用IP和端口、而是使用fd创建socket
sServerSocket = new LocalServerSocket(fd);
...
ZygoteInit#registerZygoteSocket()
static void preload()
preloadClasses(); // 加载所需的各种class文件
preloadResources(); // 加载资源文件
preloadOpenGL(); // 初始化OpenGL
preloadSharedLibraries(); // 加载系统Libraries
preloadTextResources(); //加载文字资源
WebViewFactory.prepareWebViewInZygote(); // 初始化WebView
启动SystemServer进程
跟进startSystemServer()
private static boolean startSystemServer(String abiList, String socketName) throws MethodAndArgsCaller, RuntimeException
long capabilities = posixCapabilitiesAsBits(
OsConstants.CAP_BLOCK_SUSPEND,
OsConstants.CAP_KILL,
...
);
/* Hardcoded command line to start the system server */
String args[] =
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"com.android.server.SystemServer",
;
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try
parsedArgs = new ZygoteConnection.Arguments(args);
// 打开系统调试属性
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
// 请求fork SystemServer进程
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
catch (IllegalArgumentException ex)
throw new RuntimeException(ex);
// pid为0表示子进程,即SystemServer进程,从此SystemServer进程与Zygote进程分道扬镳
if (pid == 0)
if (hasSecondZygote(abiList))
waitForSecondaryZygote(socketName);
handleSystemServerProcess(parsedArgs);
return true;
前面一大段都在构造参数,直接进到try
中的代码块。首先根据args
数组构造了一个ZygoteConnection.Arguments
,然后根据parsedArgs
对象的各种参数调用Zygote#forkSyatemServer()
方法fork
出第一个子进程,也就是SystemServer
进程。最后通过执行handleSystemServerProcess
反射调用SystemServer#main()
。可以看到,这段代码最主要的作用就是fork
出SystemServer
进程。这里还看不出反射调用的具体细节,下文会一一分析。
首先看下构造ZygoteConnection.Arguments
对象时,具体都做了哪些工作,尤其关注Zygote#forkSystemServer()
中几个参数的值。
源码位置:frameworks/base/core/java/com/android/internal/os/ZygoteConnection$Arguments.java
Arguments(String args[]) throws IllegalArgumentException
parseArgs(args);
private void parseArgs(String args[]) throws IllegalArgumentException
int curArg = 0;
boolean seenRuntimeArgs = false;
for ( /* curArg */ ; curArg < args.length; curArg++)
String arg = args[curArg];
if (arg.equals("--"))
curArg++;
break;
else if (arg.startsWith("--setuid="))
if (uidSpecified)
throw new IllegalArgumentException("Duplicate arg specified");
uidSpecified = true;
uid = Integer.parseInt(arg.substring(arg.indexOf('=') + 1));
else if (arg.startsWith("--setgid="))
if (gidSpecified)
gidSpecified = true;
gid = Integer.parseInt(arg.substring(arg.indexOf('=') + 1));
else if (arg.startsWith("--target-sdk-version="))
targetSdkVersionSpecified = true;
targetSdkVersion = Integer.parseInt(arg.substring(arg.indexOf('=') + 1));
...
else if (arg.equals("--runtime-args"))
seenRuntimeArgs = true;
else if (arg.startsWith("--capabilities="))
capabilitiesSpecified = true;
String capString = arg.substring(arg.indexOf('=')+1);
String[] capStrings = capString.split(",", 2);
if (capStrings.length == 1)
effectiveCapabilities = Long.decode(capStrings[0]);
permittedCapabilities = effectiveCapabilities;
else
permittedCapabilities = Long.decode(capStrings[0]);
effectiveCapabilities = Long.decode(capStrings[1]);
else if (arg.startsWith("--setgroups="))
String[] params = arg.substring(arg.indexOf('=') + 1).split(",");
gids = new int[params.length];
for (int i = params.length - 1; i >= 0 ; i--)
gids[i] = Integer.parseInt(params[i]);
else if (arg.startsWith("--nice-name="))
niceName = arg.substring(arg.indexOf('=') + 1);
else
break;
// 保存没有被解析的参数
remainingArgs = new String[args.length - curArg];
System.arraycopy(args, curArg, remainingArgs, 0, remainingArgs.length);
对比传入的args
数组,可以发现:parsedArgs.uid=1000
、parsedArgs.gid=1000
、parsedArgs.gids="1001","1002",..."3007"
、parsedArgs.gid=1000
、parsedArgs.niceName=system_server
、parsedArgs.seenRuntimeArgs=true
。如果中途结束,保存未解析的参数至remainingArgs
数组。
获得Arguments
对象之后,就开始请求创建SystemServer
进程。
源码位置:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
ZygoteInit#handleSystemServerProcess()
private static void handleSystemServerProcess(
ZygoteConnection.Arguments parsedArgs)
throws ZygoteInit.MethodAndArgsCaller
closeServerSocket();
if (parsedArgs.niceName != null)
Process.setArgV0(parsedArgs.niceName);
...
// 默认为null
if (parsedArgs.invokeWith != null)
...
else
...
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
/* should never reach here */
由Zygote
创建的子进程默认拥有Zygote
进程的Socket
对象,而子进程又用不上,所以先调用closeServerSocket()
关闭它。上一段参数解析时写道:parsedArgs.niceName=system_server
,在这里调用Process.setArgV0()
设置进程名为:system_server
。由于parsedArgs.invokeWith
属性默认为null
,最后调用RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl)
来进一步启动SystemServer
,这里的参数parsedArgs.remainingArgs
就是上文中保存没有被解析对象的数组。
源码位置:frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
RuntimeInit#zygoteInit()
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller
// 重定向Log输出
redirectLogStreams();
//初始化运行环境
commonInit();
//启动Binder线程池
nativeZygoteInit();
//调用程序入口函数
applicationInit(targetSdkVersion, argv, classLoader);
RuntimeInit#applicationInit()
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller
// 初始化虚拟机环境
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
final Arguments args;
try
args = new Arguments(argv);
catch (IllegalArgumentException ex)
return;
// Remaining arguments are passed to the start class's static main
invokeStaticMain(args.startClass, args.startArgs, classLoader);
RuntimeInit#invokeStaticMain()
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller
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
// 获取main方法
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);
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
这里传入的className
就是com.android.server.SystemServer
,然后获取main
方法,接着判断修饰符,必须是static
而且必须是public
类型。最有意思的莫过于做完这一切之后,抛出了个MethodAndArgsCaller
异常。辛苦辛苦各种初始化,各种变着法儿的调用,最后你居然给我抛个异常!!先别急,这个异常在Zygote#main()
方法中捕获。这么做的作用是清除应用程序进程创建过程的调用栈。
public static void main(String argv[])
try
...
startSystemServer(abiList, socketName);
...
catch (MethodAndArgsCaller caller)
caller.run();
跟进MethodAndArgsCaller#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);
我就说要出大事情!我就说要出大事情!!我就说要出大事情!!!可以看到在这里通过反射调用了com.android.server.SystemServer#main(String[] args)
。至此,Zygote
进程for
出SystemServer
进程,并成功调用SystemServer#main()
。
现在SystemServer
进程也创建了,main
方法也调用了。Zygote
进程的使命就此完结了吗?上文我们说道:所有的应用进程和SystemServer
进程都是由Zygote
进程fork
而来。现在有关SystemServer
进程的已经告一段落,那有关应用进程呢?
让我们再次回到ZygoteInit#main()
public static void main(String argv[])
...
startSystemServer(abiList, socketName);
runSelectLoop(abiList);
closeServerSocket();
main
方法中前面所有的代码好像都和应用进程没有关系,最后一行又是关闭socket
,看来和应用进程相关的设置都在runSelectLoop()
中,跟进。
监听Socket,启动应用进程
ZygoteInit#runSelectLoop()、ZygoteInit#acceptCommandPeer()
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
FileDescriptor[] fdArray = new FileDescriptor[4];
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
int loopCount = GC_LOOP_COUNT;
while (true)
int index;
if (loopCount <= 0)
gc();
loopCount = GC_LOOP_COUNT;
else
loopCount--;
try
fdArray = fds.toArray(fdArray);
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(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDescriptor());
else
boolean done;
done = peers.get(index).runOnce();
if (done)
peers.remove(index);
fds.remove(index);
private static ZygoteConnection acceptCommandPeer(String abiList)
try
return new ZygoteConnection(sServerSocket.accept(), abiList);
catch (IOException ex)
throw new RuntimeException("IOException during accept()", ex);
这里有个死循环,一直监听socket
,然后调用ZygoteConnection#runOnce()
,从函数名runOnce
上感觉真相就要呼之欲出了,跟进。
源码位置:frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
ZygoteConnection#runOnce()
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller
String args[];
args = readArgumentList();
parsedArgs = new Arguments(args);
try
...
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
parsedArgs.appDataDir);
catch (ErrnoException ex)
logAndPrintError(newStderr, "Exception creating pipe", ex);
catch (IllegalArgumentException ex)
logAndPrintError(newStderr, "Invalid zygote arguments", ex);
catch (ZygoteSecurityException ex)
logAndPrintError(newStderr,
"Zygote security policy prevents request: ", ex);
try
if (pid == 0)
// in child
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
// should never get here, the child is expected to either
// throw ZygoteInit.MethodAndArgsCaller or exec().
return true;
else
// in parent...pid of < 0 means failure
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
finally
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
和启动SystemServer
进程类似。这里调用Zygote#forkAndSpecialize()
创建应用进程,而参数parsedArgs
是通过socket
一行行读出来的。详见ZygoteConnection#readArgumentList()
private String[] readArgumentList() throws IOException
int argc;
try
String s = mSocketReader.readLine();
if (s == null)
return null;
argc = Integer.parseInt(s);
catch (NumberFormatException ex)
throw new IOException("invalid wire format");
if (argc > MAX_ZYGOTE_ARGC)
throw new IOException("max arg count exceeded");
String[] result = new String[argc];
for (int i = 0; i < argc; i++)
result[i] = mSocketReader.readLine();
if (result[i] == null)
// We got an unexpected EOF.
throw new IOException("truncated request");
return result;
因为还没有看发送Socket
消息的源码,这里斗胆猜测:应该是uid、gid、niceName等参数。
通过Socket
读取完各种参数之后,调用ZygoteConnection#handleChildProc()
,创建完应用程序进程之后就该调用应用程序的入口方法了。跟进。
private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller
// 关闭从Zygote进程复制过来的Socket连接
closeSocket();
ZygoteInit.closeServerSocket();
if (parsedArgs.niceName != null)
Process.setArgV0(parsedArgs.niceName);
...
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, null /* classLoader */);
最后调用RuntimeInit#zygoteInit()
,后面的就和SystemServer
启动流程类似。感兴趣的同学自行查看。
总结一下Zygote
启动流程:
初始化DDMS
注册
Zygote
进程的Socket
加载
class
、resource
、OpenGL
、WebView
等各种资源fork
出SystemServer
进程启动
SystemServer
进程调用
runSelectLoop()
一直监听Socket
信息收到创建应用程序
Socket
消息,调用ZygoteConnection#runOnce()
。在runOnce()
中调用Zygote#forkAndSpecialize()
创建应用进程启动应用进程
更多Framework源码解析,请移步 Framework源码解析系列[目录]
以上是关于Android Zygote启动流程源码解析的主要内容,如果未能解决你的问题,请参考以下文章
Android5 Zygote 与 SystemServer 启动流程分析