理解Android系统启动之Init、Zygote、SystemServer

658 阅读7分钟

理解Android系统启动之Init、Zygote、SystemServer

1. Init

1.1 init 是Linux系统中用户控件的第一个进程。

职责:
1.init进程创建系统中的几个关键进程,如zygote进程
2.Android系统中有很多属性,于是inti提供了一个property service(属性服务)来管理它们

1.2 init的工作流程可以概括为

  1. 解析两个配置文件,我们将分析其中对init.rc文件的解析
  2. 执行各个阶段的动作,创建zygote的工作就是在其中的某个阶段完成的。
  3. 调用property_init初始化属性相关的资源,并且通过property_start_server启动属性服务
  4. 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,这个socketlistenaccept 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函数