理解Android系统启动之Init、Zygote、SystemServer
1. Init
1.1 init 是Linux系统中用户控件的第一个进程。
职责:
1.init进程创建系统中的几个关键进程,如zygote进程
2.Android系统中有很多属性,于是inti提供了一个property service(属性服务)来管理它们
1.2 init的工作流程可以概括为
- 解析两个配置文件,我们将分析其中对init.rc文件的解析
- 执行各个阶段的动作,创建zygote的工作就是在其中的某个阶段完成的。
- 调用property_init初始化属性相关的资源,并且通过property_start_server启动属性服务
- init进入一个无限循环,并且等待一些事情发生。重点关注init如何处理来自socket和来自属性服务器的相关事情。
1.3 解析配置文件
init会解析两个配置文件,一个是init.rc,另一个与硬件平台相关。解析配置文件调用的parse_config_file函数。这个函数中主要是读取配置文件(read_file),读取结束后调用parse_config函数进行真正的解析。
parse_config函数
keyword.h文件中定义了init中使用关键字通过两次包含得到了一个keyword_info结构体数组。
zygote是由init进程fork并且execv(这时会传入一个环境变量,在ZygoteInit.java的main方法中会用到)后创建的。
zygote进程死后、它的父进程init会找到代表zygote的那个service并且杀掉zygote创建的所有子进程,Java世界也就崩溃了。
zygote的重启,zygote死的时候会将service结构体的flags设置为SVC_RESTARTING;
inti.c::main函数中有一个代码片段
for(;;){
int nr, i, timeout = -1;
for (i = 0; i < fd_count; i++}
ufds[i].revents = 0;
drain_action_queue () ; //poll A数返回后,会进入下一轮的循环
restart_processes () ; // 这里会重启所有 flag 标志为 SVC_RESTARTING的 service。
}
这样,zygote就重启了。
2. zygote
2.1 zygote分析
zygote是由init进程分局ini.rc文件中配置项创建的。
zygote最初的名字叫“app_process”,这是在Android.mk文件中指定的,但是在运行过程中app_process通过Linux下的pctrl系统调用将自己的名字换成了zygote,所以通过ps命令看它的进程名是zygote,它的原型app_process对应的源文件是App_mian.cpp。
zygote的main函数比较简单,其中主要是更换了名称,它的重要功能是由AppRuntime的start来完成的。
2.2 AppRuntime分析
AppRuntime类的生命在App_main.cpp中,它是从AndroidRuntime类派生出来的。
它重载了onStarted、onZygoteInit和onExit函数。
zygote的代码中调用了AppRuntime类的start方法。
在AppRuntime类的start方法中主要进行了三部操作
1.创建虚拟机startVm
2.注册JIN函数startReg
3.通过JNI调用Java函数,注意调用的函数是main,所属的类是com.android.internal.os.ZygoteInit,传递的参数是
“com.android.internal.os.ZygoteInit true”,
调用ZygoteInit的main函数后,Zygote便进入了Java世界!
CallStaticVoidMethod(startClass,startMeth, strArra)
2.2.1 创建虚拟机startVm
这个函数就是调用JNI的虚拟机创建函数,但是在创建虚拟机的一些参数是在startVm中确定的
2.2.2 注册JIN函数startReg
Java世界用到的一些函数是采用native方式实现的,所以要提前注册这些函数。
2.2.3 CallStaticVoidMethod(startClass,startMeth, strArra) 进入Java世界
1.建立IPC通信服务器--registerZygoteSocket。
在这个函数调用过程中会创建服务端Socket,这个socket将listen并accept Client
2.预加载类和资源---preloadClasses和preloadResources函数
preloadClasses函数用来加载PRELOADED_CLASSES变量中的类信息,
加载类用的是Java反射技术(它的值为"preloaded-classes),
用coolfind在framework中搜索名为“preloaded-classes”的文件,
最后会在framework/base目录下找到。它是一个文本文件,内容如下:
# Classes which are preloaded bycom.android.internal.os.ZygoteInit.
# Automatically generated by
# frameworks/base/tools/preload/WritePreloadedClassFile.java.
# MIN_LOAD_TIME_MICROS=1250 //超时控制
android.R$styleable
android.accounts.AccountManager
android.accounts.AccountManager$4
android.accounts.AccountManager$6
android.accounts.AccountManager$AmsTask
android.accounts.AccountManager$BaseFutureTask
android.accounts.AccountManager$Future2Task
android.accounts.AuthenticatorDescription
android.accounts.IAccountAuthenticatorResponse$Stub
android.accounts.IAccountManager$Stub
android.accounts.IAccountManagerResponse$Stub
......//一共有1268行
preloadResources和preloadClass类似,它主要是加载framework-res.apk中的资源。
说明:在UI编程中常使用的com.android.R.XXX资源,是系统默认的资源,它们就是由Zygote加载的。
2.3 启动system_server--startSystemServer()
这个函数会创建Java世界中的系统Service所驻留的进程system_server,该进程是framework的核心。如果它死了,会导致zygote自杀。
[-->ZygoteInit.java]
private static boolean startSystemServer()
throws MethodAndArgsCaller, RuntimeException {
//设置参数
String args[] = {
"--setuid=1000",//uid和gid等设置
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,
3001,3002,3003",
"--capabilities=130104352,130104352",
"--runtime-init",
"--nice-name=system_server", //进程名,叫system_server
"com.android.server.SystemServer", //启动的类名
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
//把上面字符串数组参数转换成Arguments对象。具体内容请读者自行分析。
parsedArgs = new ZygoteConnection.Arguments(args);
int debugFlags = parsedArgs.debugFlags;
//fork一个子进程,看来,这个子进程就是system_server进程。
pid = Zygote.forkSystemServer(//这个函数下面会讲到
parsedArgs.uid,parsedArgs.gid,
parsedArgs.gids,debugFlags, null);
}catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/*
关于fork的知识,请读者务花些时间去研究。如果对fork具体实现还感兴趣,可参考
《Linux内核源代码情景分析》一书。(该书由浙江大学出版社出版,作者为毛德操、胡希明)
下面代码中,如果pid为零,则表示处于子进程中,也就是处于system_server进程中。
*/
if(pid == 0) {
//① system_server进程的工作
handleSystemServerProcess(parsedArgs);
}
//zygote返回true
return true;
}
2.4 有求必应之等待请求--runSelectLoopMode
在第一个关键点registerZygoteSocket中注册了一个用于IPC的Socket,不过那时还没有地方用到它。它的用途将在这个runSelectLoopMode中体现出来.
runSelectLoopMode比较简单,就是:
1.处理客户连接和客户请求。其中客户在Zygote中用ZygoteConnection对象来表示。
2.客户的请求由ZygoteConnection的runOnce来处理。 建议:runSelectLoopMode比较简单,但它使用的select的背后所代表的思想却并非简单。建议读者以此为契机,认真学习常用的I/O模型,包括阻塞式、非阻塞式、多路复用、异步I/O等,掌握这些知识,对于未来编写大型系统很有帮助。
关于Zygote的总结
Zygote是创建Android系统中Java世界的盘古,它创建了第一个Java虚拟机,同时它又是女娲,它成功地繁殖了framework的核心system_server进程。
Zygote创建Java世界的步骤:
1.创建AppRuntime对象,并调用它的start。此后的活动则由AppRuntime来控制。
2.调用startVm创建Java虚拟机,然后调用startReg来注册JNI函数。
3.通过JNI调用com.android.internal.os.ZygoteInit类的main函数,从此进入了Java世界。然而在这个世界刚开创的时候,什么东西都没有。
4.调用registerZygoteSocket。通过这个函数,它可以响应子孙后代的请求。同时Zygote调用preloadClasses和preloadResources,为Java世界添砖加瓦。
5.Zygote觉得自己工作压力太大,便通过调用startSystemServer分裂一个子进程system_server来为Java世界服务。
6.Zygote完成了Java世界的初创工作,它已经很满足了。下一步该做的就是调用runSelectLoopMode后,便沉沉地睡去了。
以后的日子:Zygote随时守护在我们的周围,当接收到子孙后代的请求时,它会随时醒来,为它们工作。
3. SystemServer分析
SystemServer是Zygote的第一个子进程,是通过Zygote.forkSystemServer函数fork诞生出来的。forkSystemServer是一个native函数,实现实在dalvik_system_Zygote.c中,实现如下:
[-->dalvik_system_Zygote.c]
static voidDalvik_dalvik_system_Zygote_forkSystemServer(
const u4* args, JValue* pResult)
{
pid_tpid;
//根据参数,fork一个子进程
pid =forkAndSpecializeCommon(args);
if (pid > 0) {
int status;
gDvm.systemServerPid = pid;//保存system_server的进程id
//函数退出前须先检查刚创建的子进程是否退出了。
if(waitpid(pid, &status, WNOHANG) == pid) {
//如果system_server退出了,Zygote直接干掉了自己
kill(getpid(), SIGKILL);
}
}
RETURN_INT(pid);
}
下面,再看看forkAndSpecializeCommon,代码如下所示:
[-->dalvik_system_Zygote.c]
static pid_t forkAndSpecializeCommon(const u4*args)
{
pid_tpid;
uid_tuid = (uid_t) args[0];
gid_tgid = (gid_t) args[1];
ArrayObject* gids = (ArrayObject *)args[2];
u4debugFlags = args[3];
ArrayObject *rlimits = (ArrayObject *)args[4];
//设置信号处理,待会儿要看看这个函数。
setSignalHandler();
pid =fork(); //fork子进程
if (pid== 0) {
//对子进程要根据传入的参数做一些处理,例如设置进程名,设置各种id(用户id,组id等)
}
......
}
最后看看setSignalHandler函数,它由Zygote在fork子进程前调用,代码如下所示:
[-->dalvik_system_Zygote.c]
static void setSignalHandler()
{
interr;
structsigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sigchldHandler;
err =sigaction (SIGCHLD, &sa, NULL);//设置信号处理函数,该信号是子进程死亡的信号
}
//我们直接看这个信号处理函数sigchldHandler
static void sigchldHandler(int s)
{
pid_tpid;
intstatus;
while((pid = waitpid(-1, &status, WNOHANG)) > 0) {
} else if (WIFSIGNALED(status)) {
}
}
//如果死去的子进程是SS,则Zygote把自己也干掉了,这样就做到了生死与共!
if(pid == gDvm.systemServerPid) {
kill(getpid(), SIGKILL);
}
}
ZygoteInit分裂产生的SS,其实就是为了调用com.android.server.SystemServer的main函数