android6.0源码分析之Zygote进程分析
Posted 古冥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android6.0源码分析之Zygote进程分析相关的知识,希望对你有一定的参考价值。
在android6.0源码分析之Runtime的初始化一文中,对Zygote进程的初期的Runtime初始化过程进行了分析,在Runtime启动结束后,会对Zygote进程进行初始化,其它Java进程都需要从Zygote进程来fork,而Zygote的初始化是从ZygoteInit的main函数开始的:
//ZygoteInit.java
public static void main(String argv[])
try
...
//注册zygote socket
registerZygoteSocket(socketName);
...
//加载资源以及类
preload();
...
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false);
//启动system server进程
if (startSystemServer)
startSystemServer(abiList, socketName);
Log.i(TAG, "Accepting command socket connections");
//循环等待创建进程的socket请求
runSelectLoop(abiList);
//关闭server socket
closeServerSocket();
catch (MethodAndArgsCaller caller) //截取MethodAndArgsCaller异常
//执行新进程的main函数
caller.run();
catch (RuntimeException ex)
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
首先它会对启动参数进行解析,得到是否需要启动systemserver,或者得到ABI_LIST_ARG参数和socketName参数等,然后则会调用registerZygoteSocket来创建一个LocalServerSocket来与以后需要systemServer创建进程时进行通信,接着调用preload来对VM虚拟机中的DEX类等资源进行加载,然后会调用runSelectLoop来进行循环等待,最后会截取ZygoteInit中抛出的MethodAndArgsCaller异常,并在异常处理时,调用新建进程的main方法实现新进程的启动。下面将对这四个主要的调用分别进行分析。
1、registerZygoteSocket方法分析
//ZygoteInit.java
private static void registerZygoteSocket(String socketName)
if (sServerSocket == null) //判断Zygote socket是否已创建
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);
//创建Zygote socket,它会在runSelectLoop中进行循环等待
sServerSocket = new LocalServerSocket(fd);
catch (IOException ex)
throw new RuntimeException("Error binding to local socket '" + fileDesc + "'", ex);
由代码可知,它创建了一个LocalServerSocket,并且它会在runSelectLoop中阻塞等待socket请求,至于runSelectLoop稍后会进行分析。
2、preload方法分析
//ZygoteInit.java
static void preload()
Log.d(TAG, "begin preload");
//加载类
preloadClasses();
//加载资源
preloadResources();
//加载OpenGL
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");
由代码可知,preload方法主要就是进行类,资源,公共库以及相关的文本资源的加载,主要分析其中的preloadClasses以及preloadSharedLibraries方法:
//ZygoteInit.java
private static void preloadClasses()
//获取虚拟机运行时
final VMRuntime runtime = VMRuntime.getRuntime();
InputStream is;
try
//初始化文件输入流,路径为"/system/etc/preloaded-classes"
is = new FileInputStream(PRELOADED_CLASSES);
catch (FileNotFoundException e)
return;
...
// Alter the target heap utilization. With explicit GCs this
// is not likely to have any effect.
float defaultUtilization = runtime.getTargetHeapUtilization();
runtime.setTargetHeapUtilization(0.8f);
try
//通过BufferReader来读取输入流
BufferedReader br = new BufferedReader(new InputStreamReader(is), 256);
int count = 0;
String line;
//逐行处理
while ((line = br.readLine()) != null)
// Skip comments and blank lines.
line = line.trim();
if (line.startsWith("#") || line.equals(""))
continue;
try
...
//加载并显示地初始化给定的类
Class.forName(line, true, null);
count++;
catch (ClassNotFoundException e)
...
catch (IOException e)
Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
finally
IoUtils.closeQuietly(is);
// Restore default.
runtime.setTargetHeapUtilization(defaultUtilization);
//将类,域,方法等填充到dex缓存中
runtime.preloadDexCaches();
首先,根据”/system/etc/preloaded-classes”来,逐行解析里面的类,最后再将预加载的类填充到VM的dex缓存中,它会调用VMRuntime库的本地方法preloadDexCaches来填充,此方法的具体实现在VM库中。
接下来看preloadSharedLibraries方法:
//ZygoteInit.java
private static void preloadSharedLibraries()
Log.i(TAG, "Preloading shared libraries...");
System.loadLibrary("android");
System.loadLibrary("compiler_rt");
System.loadLibrary("jnigraphics");
如代码,它主要进行shared库android,compiler_rt以及jnigraphics的加载。
3、 startSystemServer方法分析
System Server进程是android系统的非常重要的进程,它在Zygote的启动之后就必须启动,所以startSystemServer方法也是Zygote初始化中非常重要的调用:
//ZygoteInit.java
private static boolean startSystemServer(String abiList, String socketName)
throws MethodAndArgsCaller, RuntimeException
...
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);
//处理子进程
if (pid == 0)
if (hasSecondZygote(abiList))
waitForSecondaryZygote(socketName);
//处理system server进程
handleSystemServerProcess(parsedArgs);
return true;
它首先fork一个systemserver进程,然后再对子进程systemserver进行相关处理,首先来看forkSystemServer方法:
//Zygote.java
public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,int[][] rlimits,
long permittedCapabilities, long effectiveCapabilities)
VM_HOOKS.preFork();
//调用native方法
int pid = nativeForkSystemServer(uid, gid, gids, debugFlags, rlimits, permittedCapabilities,
effectiveCapabilities);
// Enable tracing as soon as we enter the system_server.
if (pid == 0)
Trace.setTracingEnabled(true);
VM_HOOKS.postForkCommon();
return pid;
这里将通过JNI调用,进入Native代码层,接着分析nativeForkSystemServer方法,它对应的是Native方法是com_android_internal_os_Zygote_nativeForkSystemServer:
//com_android_internal_os_Zygote.cpp
static jint com_android_internal_os_Zygote_nativeForkSystemServer(JNIEnv* env, jclass, uid_t uid,
gid_t gid, jintArray gids,jint debug_flags, jobjectArray rlimits, jlong
permittedCapabilities,jlong effectiveCapabilities)
//fork 相应进程
pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,debug_flags, rlimits,
permittedCapabilities, effectiveCapabilities,MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true,
NULL,NULL, NULL);
if (pid > 0)
gSystemServerPid = pid;
int status;
if (waitpid(pid, &status, WNOHANG) == pid)
//system server进程died,终止运行时,重启zygote进程
RuntimeAbort(env);
return pid;
它调用了ForkAndSpecializeCommon方法来进行进程的创建,最后对创建结果进行了相应的处理,这里与创建普通进程的区别就是,需要对子进程进行检查,判断system server进程是否died,如果died,则会终止runtime,并重启Zygote进程,接着分析ForkAndSpecializeCommon方法:
//com_android_internal_os_Zygote.cpp
static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
jint debug_flags, jobjectArray javaRlimits,jlong permittedCapabilities, jlong
effectiveCapabilities,jint mount_external,jstring java_se_info, jstring java_se_name,
bool is_system_server, jintArray fdsToClose,jstring instructionSet, jstring dataDir)
SetSigChldHandler();
//fork一个进程
pid_t pid = fork();
if (pid == 0) //处理子进程
// The child process.
gMallocLeakZygoteChild = 1;
...
SetGids(env, javaGids);
SetRLimits(env, javaRlimits);
...
rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
...
if (se_info_c_str != NULL)
//设置线程名称
SetThreadName(se_name_c_str);
...
//此处会post一个forkChild的消息
env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
is_system_server ? NULL : instructionSet);
else if (pid > 0)
// the parent process
return pid;
它首先fork一个子进程,然后对子进程进行处理,最后会post一个forkChild的消息出去,而在ZygoteInit中会对forksystemserver的子进程进行处理,所以,接着看handleSystemServerProcess方法:
//ZygoteInit.java
private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs)
throws ZygoteInit.MethodAndArgsCaller
...
if (parsedArgs.invokeWith != null)
String[] args = parsedArgs.remainingArgs;
if (systemServerClasspath != null)
String[] amendedArgs = new String[args.length + 2];
amendedArgs[0] = "-cp";
amendedArgs[1] = systemServerClasspath;
System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2,
parsedArgs.remainingArgs.length);
WrapperInit.execApplication(parsedArgs.invokeWith,parsedArgs.niceName,
parsedArgs.targetSdkVersion,VMRuntime.getCurrentInstructionSet(), null, args);
else
ClassLoader cl = null;
if (systemServerClasspath != null)
//获取类加载器
cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());
Thread.currentThread().setContextClassLoader(cl);
//根据参数来启动System server进程
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
由代码可知,它主要会调用RuntimeInit类的zygoteInit方法来对子进程system server进行启动的处理:
//RuntimeInit.java
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller
...
commonInit();
nativeZygoteInit();
applicationInit(targetSdkVersion, argv, classLoader);
其中commonInit主要就是进行一些系统属性的初始化或者重置,这里重点分析nativeZygoteInit和applicationInit方法。
3.1 nativeZygoteInit方法分析
nativeZygoteInit是Native方法,通过JNI调用,它的实现是com_android_internal_os_RuntimeInit_nativeZygoteInit方法:
//AndroidRuntime.cpp
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
gCurRuntime->onZygoteInit();
由代码可知,这里会回调App_main.cpp中的onZygoteInit方法:
//App_main.cpp
virtual void onZygoteInit()
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\\n");
proc->startThreadPool();
这里主要就是在进程里面启动线程池,该线程池,是为System server进程创建的,此线程池会为Binder提供支持等,这里不做分析。
3.2 ApplicationInit方法分析
//RuntimeInit.java
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller
nativeSetExitWithoutCleanup(true);
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
final Arguments args;
try
args = new Arguments(argv);
catch (IllegalArgumentException ex)
return;
//invoke system server的main方法
invokeStaticMain(args.startClass, args.startArgs, classLoader);
由代码可知,它会根据启动的参数以及类加载器来调用InvokeStaticMain方法:
//RuntimeInit.java
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) ...
Method m;
try
//获取systemserver的main方法,main方法是用来开始systemserver进程的
m = cl.getMethod("main", new Class[] String[].class );
catch (NoSuchMethodException ex) ...
...
//抛出MethodAndArgsCaller异常,而此异常在ZygoteInit的main方法中会进行扑捉,异常的处理稍后再分析
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
由代码可知,首先,通过Java的反射机制,借助传入的参数以及类加载器,从而获取systemserver进程的main方法,最后再抛出一个MethodAndArgsCaller的异常,而此异常在ZygoteInit的main方法的最后会进行截取,具体的异常处理稍后在第四节最后再分析,因为普通进程的创建也是通过抛出MethodAndArgsCaller的方法来启动的,至此startsystemserver方法就分析结束了。
4、runSelectLoop方法分析
//ZygoteInit.java
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller
//初始化文件描述符组合ZygoteConnection连接组
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
while (true) //循环等待ZygoteSocket请求并进行相应的处理
...
for (int i = pollFds.length - 1; i >= 0; --i)
if ((pollFds[i].revents & POLLIN) == 0)
continue;
if (i == 0)
//这里阻塞等待创建进程的Zygote socket请求
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
else
//执行ZygoteConnection连接
boolean done = peers.get(i).runOnce();
if (done)
//处理结束,则将此连接移除
peers.remove(i);
fds.remove(i);
此方法将会永无休止的进行执行,因为Zygote作为Java域的第一个进程,所有的进程都是由它进行fork的,在android的生命过程中,会不断有ZygoteConnection请求,所以,看runSelectLoop方法,它首先是调用acceptCommandPeer方法来获取一个ZygoteConnection连接,然后再调用ZygoteConnection的runOnce方法来执行连接处理,首先来看acceptCommandPeer方法:
//ZygoteInit.java
private static ZygoteConnection acceptCommandPeer(String abiList)
try
//创建ZygoteConnection连接,注意socket的accept阻塞接收请求
return new ZygoteConnection(sServerSocket.accept(), abiList);
catch (IOException ex)
throw new RuntimeException("IOException during accept()", ex);
由代么可知,这里是阻塞的,只有在ZygoteInit的main方法中最初注册的socket有请求时,才会执行,并会根据得到的socket连接来创建一个ZygoteConnection,所以,来看它的构造函数:
// ZygoteConnection.java
ZygoteConnection(LocalSocket socket, String abiList) throws IOException
mSocket = socket;
this.abiList = abiList;
//获取socket输出流
mSocketOutStream = new DataOutputStream(socket.getOutputStream());
//获取socket输入流
mSocketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()), 256);
//设置超时
mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);
try
peer = mSocket.getPeerCredentials();
catch (IOException ex)
throw ex;
此构造函数会创建socket的stream通道,至此ZygoteConnection就创建好了,接着看它的runOnce方法,socket请求一次,runOnce会执行一次:
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller
...
int pid = -1;
FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null;
try
parsedArgs = new Arguments(args);
if (parsedArgs.abiListQuery)
return handleAbiListQuery();
...
int [] fdsToClose = -1, -1 ;
FileDescriptor fd = mSocket.getFileDescriptor();
...
fd = ZygoteInit.getServerSocketFileDescriptor();
//fork 进程
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)
...
try
if (pid == 0)
// in child
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
//对子进程做相应处理
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
return true;
else
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
//对父进程做相应处理
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
finally
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
这里,就是创建普通进程的通道,它的分析类似于startSystemServer方法,它在最后同样会进入Java层的子进程的处理handleChildProc方法,最后还是会获取到创建进程的main方法,并且同样也是会抛出一个MethodAndArgsCaller的异常。
不管是创建systemServer进程还是创建普通进程,在处理其子进程时,都会获取创建子进程的main方法,同时最后会抛出一个MethodAndArgsCaller异常,为什么要抛出异常呢,此异常是在ZygoteInit的main函数中调用的,而main函数位于堆栈的最顶层,如果不采用抛异常的方式,而是在invokestaticMain方法中直接执行新建进程的main方法,则会浪费之前函数调用说占用的调用堆栈。接下来对MethodAndArgsCaller的run方法进行分析:
//ZygoteInit.java
public void run()
try
mMethod.invoke(null, new Object[] mArgs );
catch (IllegalAccessException ex)
...
其中,mMethod为构造MethodAndArgsCaller时,传入的方法,即之前startSystemServer或者runSelectLoop函数中获得的新建进程的main方法,所以run方法的主要作用就是执行此main方法,即进入新建进程。至此,Zygote进程分析结束,它的主要功能有初始化Runtime、fork system server进程以及通过循环等待Zygote socket的请求,来处理普通进行的创建。下面将给出时序图:
以上是关于android6.0源码分析之Zygote进程分析的主要内容,如果未能解决你的问题,请参考以下文章
android6.0源码分析之Camera API1.0初始化
android6.0源码分析之Camera API2.0下的video流程分析