背景
SystemServer进程是zygote进程启动后,主动“分裂”的第一个进程。
它负责启动大量的Android系统核心服务,其重要性不言而喻。一旦该进程崩溃,整个Android系统将重新启动。
版本
Android 6.0
一、启动SystemServer进程
在分析zygote进程时,我们知道当zygote进程进入到java世界后,在ZygoteInit.java中,将调用startSystemServer函数启动SystemServer进程,其关键代码是:
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
其中,函数forkSystemServer函数定义于Zygote.java中。
public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
..................
int pid = nativeForkSystemServer(uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
..................
}
容易看出,该函数通过调用native方法,完成实际的创建操作。
该Native方法定义于frameworks/base/core/jni/com_android_internal_os_Zygote.cpp中。
我们来看看对应的native函数。
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) {
//进行实际的“分裂”工作
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) {
//这里SystemServer进程已经创建出来,pid > 0 说明在父进程中
//将子进程SystemServer的pid存在zygote进程的全局变量中
gSystemServerPid = pid;
int status;
//小概率,SystemServer进程刚创建,就crash;此时需要重启zygote
if (waitpid(pid, &status, WNOHANG) == pid) {
ALOGE("System server process %d has died. Restarting Zygote!", pid);
RuntimeAbort(env);
}
}
return pid;
}
上述代码中,实际的“分裂”工作,由函数ForAndSpecializeCommon完成。
static pid_t ForkAndSpecializeCommon(......) {
//注册信号监听器
SetSigChldHandler();
..........
pid_t pid = fork();
if (pid == 0) {
//根据传入参数进行对应的处理,例如设置进程名,设置各种id(用户id,组id)等
........
//反注册掉信号监听器
UnsetSigChldHandler();
......
} else if () {
.......
}
return pid;
从上面的代码可以看出,ForkAndSpecializeCommon最终是通过fork的方式,分裂出子进程。
这里需要关注一下的是,在zygote进程fork之前,调用SetSigChldHandler函数注册了一个子进程信号监听器。由于子进程共享父进程中的堆及栈信息,因此在子进程中也会有相应的信号处理器。
为了避免该信号监听器对子进程的影响,可以看到在子进程中进行了UnsetSigChldHandler的操作。
接下来,我们看看SetSigChldHandler进行了哪些操作。
static void SetSigChldHandler() {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SigChldHandler;
//该信号监听器关注子进程结束,对应的处理函数为SigChldHandler
int err = sigaction(SIGCHLD, &sa, NULL);
if (err < 0) {
ALOGW("Error setting SIGCHLD handler: %s", strerror(errno));
}
}
从上面的代码可以看出,SetSigChldHandler函数将注册一个信号处理器,来监听子进程的死亡。当子进程死亡后,利用SigChldHandler进行操作。需要注意的是,zygote的信号监听器,关注的是zygote所有的子进程,而不只是SystemServer进程(每次创建一个新的进程时,zygote都会注册对应的监听器)。
SigChldHandler中的重要代码如下所示:
static void SigChldHandler(int /*signal_number*/) {
.......
//监听的pid为-1,表示监听任何子进程结束
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
//通过status判断子进程结束的原因,并打印相应的log
........
//上文已经介绍过,gSystemServerPid中记录了SystemServer的pid
if (pid == gSystemServerPid) {
ALOGE("Exit zygote because system server (%d) has terminated", pid);
//如果结束的子进程为SystemServer, zygote也将结束自己
kill(getpid(), SIGKILL);
}
}
.........
}
这里的问题是,所有zygote的子进程中,zygote只关心了Sys