android6.0源码分析之Zygote进程分析

时间:2023-01-01 16:48:49

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进程分析