Android启动过程 - init.rc处理过程(一)

上一篇我们知道init.rc在core/init/init.cpp,也就是init进程的SecondStageMain阶段解析和执行的。本篇我们看下执行的具体过程。

本文基于内核版本kernel/arm64 - android-amber-intel-linux--android11分支。

为了更好理解对rc文件的执行过程,需要了解rc文件本身的语法和作用

一、init.rc文件语法说明(AIL语法)

rc文件使用的是Android Init Language (AIL)语言。

core/init/README.md对rc文件做了很好的介绍。

整理如下:

(或见https://android.googlesource.com/platform/system/core/+/master/init/README.md

Android Init Language包含五类语句:

Actions, Commands, Services, Options, and Imports.

Action和Service是主要的任务执行单位。其隐式地声明了一个section,一个section下有属于它的commands和options。其中Service名称(name)唯一。如果一个Service声明了一个已存在的name,则被忽略。

  • Actions:由一些列command指令组成。Action会由trigger或property值的匹配,来决定action何时被执行。当条件被触发,多个符合条件的action将被按声明顺序依次加入一个“执行队列①”中,并按顺序执行。每个action的command指令也是按顺序执行。
    Action的格式:
    on <trigger> [&& <trigger>]*
       <command>
       <command>
       <command>

有时候在表述时,Action和trigger有时会混用,其实指的是一个事情。trigger指的是触发该action的条件,而action指的是触发该条件后,要执行的整个代码段。

  • Triggers:用于匹配某些事件,从而触发一个Action。Triggers由event trigger和property trigger组成(比如上面Action的例子)。

        event trigger可以由rc文件里的`trigger`命令触发,或者在代码里调用`QueueEventTrigger`函数触发。以一个简单的字符串来代表一个event trigger,例如“boot”或者“late-init”。

        Property triggers是当某个property的值变为了所指定的值后触发。格式为'property:<name>=<value>'、'property:<name>=\*'

比如,在一个rc文件中作了如下声明:

    on boot
       setprop a 1
       setprop b 2

    on boot && property:true=true
       setprop c 1
       setprop d 2

    on boot
       setprop e 1
       setprop f 2

当boot这个trigger触发了(在程序中通过代码调用,或者在rc中被其他action所触发),并且"true"(这是一个属性名)这个property等于"true"(属性的值), 则执行的结果为:

    setprop a 1
    setprop b 2
    setprop c 1
    setprop d 2
    setprop e 1
    setprop f 2

当boot触发了,但是"true"这个property不等于"true",那么执行结果为:

    setprop a 1
    setprop b 2
    setprop e 1
    setprop f 2

后期即使通过设置,使得property:true=true,该段代码也不会再执行了, 因为boot已经是一个执行过的event。

  • Service:是由init进程来启动或restart(当他们退出了)的程序。格式如下:
    service <name> <pathname> [ <argument> ]*
       <option>
       <option>
       ...
  • Options

        Options影响init进程在什么时候、何种方式来运行service

        指令集太长,详细说明见README,这里以启动zygote里涉及到的几个为例感受下:

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    onrestart restart wificond
    task_profiles ProcessCapacityHigh MaxPerformance
    critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

上面几个涉及到的options:

class:为service指定一个class名称。指定了同一class的service将会被一起start或者stop。如果未指定class选项,则service默认class为“default”。所有开机动画、关机动画锁需要的service都应该指定“animation”这个class。由于这些service启动得太早,将不被允许访问/data。

priority:设置该service的进程优先级。取值在-20~19之间。默认0。(通过 setpriority())

user:设置进程的user。默认root

group:设置进程的group(通过 setgroups())

socket:创建一个名为 /dev/socket/name 的domain socket(本地socket),并将fd传给当前进程。在启动service过程中同步创建。...

onrestart:在service restart时要执行的命令。

task_profiles:Set task profiles.即对进程的cgroup情况做相应设置。对task_profile的详细描述,见Cgroup 抽象层  |  Android 开源项目  |  Android Open Source Project

critical:指明本服务对设备来说是至关重要的。如果在window指定的分钟数(默认为4)内crash超过4次,则重启进入target指定模式(默认为bootloader,即fastboot)。

...

  • 触发次序。init进程在early boot阶段会按如下次序触发相应trigger(称为build-in triggers),这些trigger是在init.cpp里通过QueueEventTrigger函数调用的:

`early-init`:第一个执行的trigger,在cgroups配置之后,但在ueventd冷启动完成之前触发。

`init` :在冷启动完成后触发

`charger`:如果`ro.bootmode == "charger"`触发

`late-init`:如果`ro.bootmode != "charger"或者在charging模式下由`healthd触发了boot时触发。

其他build-in trigger还有userspace-reboot-resumeuserspace-reboot-requestedshutdown

其他的triggers是在init.rc里配置的,称为非build-in triggers。默认要执行的序列在on late-init中指定

1. `early-fs` - Start vold.

2. `fs` - Vold is up. Mount partitions not marked as first-stage or latemounted.

3. `post-fs` - Configure anything dependent on early mounts.

4. `late-fs` - Mount partitions marked as latemounted.

5. `post-fs-data` - Mount and configure `/data`; set up encryption. `/metadata` is

      reformatted here if it couldn't mount in first-stage init.

6. `zygote-start` - Start the zygote.

7. `early-boot` - After zygote has started.

8. `boot` - After `early-boot` actions have completed.

见init.rc内的相关内容:

# Mount filesystems and start core system services.
on late-init
    trigger early-fs
    # Mount fstab in init.{$device}.rc by mount_all command. Optional parameter
    # '--early' can be specified to skip entries with 'latemount'.
    # /system and /vendor must be mounted by the end of the fs stage,
    # while /data is optional.
    trigger fs
    trigger post-fs
    # Mount fstab in init.{$device}.rc by mount_all with '--late' parameter
    # to only mount entries with 'latemount'. This is needed if '--early' is
    # specified in the previous mount_all command on the fs stage.
    # With /system mounted and properties form /system + /factory available,
    # some services can be started.
    trigger late-fs
    # Now we can mount /data. File encryption requires keymaster to decrypt
    # /data, which in turn can only be loaded when system properties are present.
    trigger post-fs-data
    # Should be before netd, but after apex, properties and logging is available.
    trigger load_bpf_programs
    # Now we can start zygote.
    trigger zygote-start
    # Remove a file to wake up anything waiting for firmware.
    trigger firmware_mounts_complete
    trigger early-boot
    trigger boot
  • Commands一系列命令,可查阅Readme,不做赘述。
  • Imports:引用其他rc文件。可以是绝对rc文件名,也可以是一个目录,当为目录是,会引入改目录下所有rc文件。但不支持嵌套的子目录。对于引用后的执行顺序,通过伪代码示例如下:
fn Import(file)
      Parse(file)
      for (import : file.imports)
        Import(import)

    Import(/system/etc/init/hw/init.rc)
    Directories = [/system/etc/init, /system_ext/etc/init, /vendor/etc/init, /odm/etc/init, /product/etc/init]
    for (directory : Directories)
      files = <Alphabetical order of directory's contents>
      for (file : files)
        Import(file)

Action的执行顺序取决于它什么时候被解析(Parse)。从上面的逻辑看,本文件先被解析,再解析本文件所import的文件。也就是说,如果一个‘post-fs-data’ action被定义在主文件,同时主文件所引用(import)的rc文件中也有post-fs-data,那么执行顺序是主文件内的post-fs-data先执行,再执行import文件内的post-fs-data

  • Properties。见README
  • 其他诸如Boot timingBootchartingSystrace等用户记录启动过程信息。
  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值