Android系统启动(二)-Init篇

经过前面的开篇介绍,我们对android系统启动有了一个初步的了解。那么接下来会详细分析几个关键过程。

一、Init简介

init进程是Android系统中用户空间的第一个进程(pid=1),它是用户进程的鼻祖,负责孵化各种属性服务、守护进程也包括非常重要的Zygote。init进程是由多个源文件共同组成的,这些文件位于源码目录system/core/init。本文将基于Android7.0源码来分析Init进程。

二、Init分析

当内核完成系统设置,它首先在系统文件中寻找”init”文件,最后会调用 /system/core/init/Init.cpp 的 main() 方法。它是init的入口函数。那么来看init.cpp main方法:

int main(int argc, char** argv) {
   …
    //创建文件并挂载
    if (is_first_stage) {
        mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
        mkdir("/dev/pts", 0755);
        mkdir("/dev/socket", 0755);
        mount("devpts", "/dev/pts", "devpts", 0, NULL);
        #define MAKE_STR(x) __STRING(x)
        mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
        mount("sysfs", "/sys", "sysfs", 0, NULL);
    }
    ...
    //初始化属性相关资源
    property_init();
    ...
    //启动属性服务
    start_property_service();
   ...
    Parser& parser = Parser::GetInstance();
    ...
    //解析init.rc配置文件
    parser.ParseConfig("/init.rc");
    ...
    return 0;
}

主要关注两点:初始化和启动属性服务、解析init.rc配置文件并启动zygote进程。

2.1 属性服务

Android提供的属性服务类似于Windows平台上注册表管理器的机制,内容采用键值对的形式来记录用户、软件的一些使用信息。即使系统或者软件重启,它还是能够根据之前在注册表中的记录,进行相应的初始化工作。应用程序可以通过这个属性机制,查询或者设置相应的属性。我们可以使用getprop命令来查看当前系统中都有哪些属性。

    //初始化属性相关资源
    property_init();
    ...
    //启动属性服务
    start_property_service();

此处初始化并启动了属性服务,代码细节不追究,了解下结论。

2.2 解析init.rc配置文件并启动zygote进程
2.2.1 了解Android Init Language

init.rc是一个配置文件,内部由Android初始化语言(Android Init Language)编写的脚本。先来学习下AIL:
它主要包含四种类型语句:ActionCommandsServicesOptions

Action(动作): 通过trigger,即以 on开头的语句,决定何时执行相应的service。

  • on early-init; 在初始化早期阶段触发;
  • on init; 在初始化阶段触发;
  • on late-init; 在初始化晚期阶段触发;
  • on boot/charger: 当系统启动/充电时触发,还包含其他情况,此处不一一列举;
  • on property:=: 当属性值满足条件时触发;

启动顺序:on early-init -> init -> late-init -> boot

Service(服务):是一个程序,他在初始化时启动,并在退出时重启(可选),由init进程启动,一般运行于另外一个init的子进程,所以启动service前需要判断对应的可执行文件是否存在。init生成的子进程,定义在rc文件,其中每一个service,在启动时会通过fork方式生成子进程。

例: service servicemanager(服务名 ) /system/bin/servicemanager ( 路径)

Command(命令): 要执行的命令

常用的命令:

  • class_start : 启动属于同一个class的所有服务;
  • start : 启动指定的服务,若已启动则跳过;
  • stop : 停止正在运行的服务
  • setprop :设置属性值
  • mkdir :创建指定目录
  • symlink : 创建连接到符号链接;
  • write : 向文件path中写入字符串;
  • exec: fork并执行,会阻塞init进程直到程序完毕;
  • exprot :设定环境变量;
  • loglevel :设置log级别

Option(选项):Options是Services的可选项,与service配合使用

  • disabled: 不随class自动启动,只有根据service名才启动;
  • oneshot: service退出后不再重启;
  • user/group: 设置执行服务的用户/用户组,默认都是root;
  • class:设置所属的类名,当所属类启动/退出时,服务也启动/停止,默认为default;
  • onrestart:当服务重启时执行相应命令;
  • socket: 创建名为/dev/socket/的socket
  • critical: 在规定时间内该service不断重启,则系统会重启并进入恢复模式

default: 意味着disabled=false,oneshot=false,critical=false。

Action与Option配合使用

on  
    
    

举例:

on boot
    ifup lo
    hostname localhost
    domainname localdomain
    class_start default

Service与Command配合使用

service   [  ]* 
          

举例:

service healthd /sbin/healthd
    class core
    critical
    seclabel u:r:healthd:s0
    group root system wakelock

另外还有个import,它的作用是导入其他rc文件。

//init.rc 中
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc
2.2.2 zygote进程的启动

回到解析init.rc配置文件:

parser.ParseConfig("/init.rc”);

这个parser即init_parse.cpp,通过它对init.rc进行解析。在Android 7.0中对init.rc文件进行了拆分,每个服务一个rc文件。我们要分析的zygote服务的启动脚本则在system/core/rootdir/init.zygoteXX.rc中定义,这里拿64位处理器为例,init.zygote64.rc的代码如下所示:

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
   class main
   socket zygote stream 660 root system
   onrestart write /sys/android_power/request_state wake
   onrestart write /sys/power/state on
   onrestart restart audioserver
   onrestart restart cameraserver
   onrestart restart media
   onrestart restart netd
   writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks

通过init_parser.cpp完成整个service解析工作,此处就不详细展开讲解析过程,该过程主要是创建一个名”zygote”的service结构体,一个socketinfo结构体(用于socket通信),以及一个包含4个onrestart的action结构体。

Zygote服务会随着main class的启动而启动,退出后会由init重启zygote,即使多次重启也不会进入recovery模式。zygote所对应的可执行文件是/system/bin/app_process64,通过调用pid =fork()创建子进程,通过execve(svc->args[0], (char)svc->args, (char) ENV),进入App_main.cpp的main()函数。故zygote是通过fork和execv共同创建的。

流程如下:

Android系统启动(二)-Init篇_第1张图片

app_main.cpp的main()方法中,最终通过Androidrumtime来启动zygote进程。

2.3 服务重启

init进程会启动很多native的service,这些service如果不是oneshot的,当service出现异常挂掉后,init需要将其重新启动起来:

Android系统启动(二)-Init篇_第2张图片
from gityuan

具体操作不详细跟了,了解一下结论:

所有的Service里面只有servicemanager ,zygote ,surfaceflinger这3个服务有onrestart关键字来触发其他service启动过程。

//zygote可触发media、netd以及子进程(包括system_server进程)重启
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd

//servicemanager可触发healthd、zygote、media、surfaceflinger、drm重启
service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart drm

//surfaceflinger可触发zygote重启
service surfaceflinger /system/bin/surfaceflinger
    class core
    user system
    group graphics drmrpc
    onrestart restart zygote 

所以,surfaceflinger、servicemanager、system_server以及zygote自身进程被杀都会触发Zygote重启。

总结init的主要工作:
1.创建一些文件夹并挂载设备。
2.初始化和启动属性服务。
3.通过解析init.rc 和 其他对应rc文件,启动对应的系统级进程。其中包括后面要讲的zygote。

本文基于Android7.0源码分析。

参考:
https://blog.csdn.net/freekiteyu/article/details/79175010
http://liuwangshu.cn/framework/booting/1-init.html

系列文章:
Android系统启动(一)-开篇
Android系统启动(二)-Init篇
Android系统启动(三)-Zygote篇
Android系统启动(四)-SystemServer篇
Android系统启动(五)-ActivityManagerService篇
Android系统启动(六)-Launcher篇

你可能感兴趣的:(Android系统启动(二)-Init篇)