Physical Address:
ChongQing,China.
WebSite:
无论是在Android系统还是在Linux系统中,rc启动文件都是一个非常重要的东西。在这些启动文件内,规定了我们的系统在开机过程中所要完成的一些事,今天这篇文章将对Android系统中的rc启动文件做一个解析。
安卓系统的启动由Linux系统的启动演化而来。在系统上电后,系统内核就开始解析配置文件(也就是init.rc),这一块儿的源代码位于system/core/init/init.c内。
在main函数内,会逐次执行restart_processes- >restart_service_if_needed->service_start这些函数,逐步完成整个系统的启动。
大体上流程可以以下图表示:
在Linux与Android系统内,用户态与内核态需要进行数据交互,而很多这些交互实际上都需要文件作为沟通媒介(Linux系统的哲学:一切皆文件)。在内核启动以后,往往会立即跟用户态的程序进行数据交换,所在在我们内核启动的过程中就需要创建好这些文件,那么rc文件主要的作用就是创建这些用于通信的文件(包括分区挂载)并对其做相关操作的,当然也包含一些对系统服务的操作。
需要说明的是,rc启动文件并不是源码文件,rc启动文件只是满足了特定语法规则的解释文件,用于描述系统在某个环节执行相应的操作。在我们的系统内,rc启动文件其实有很多个。在系统启动过程重根目录下的init.rc是最先被加载执行的启动文件,其会被init进程加载。
在init进程中,会mount包括/system、/vendor等分区。在加载init.rc之后会接着加载/system/etc/init、/vendor/etc/init以及/odm/etc/init、/product/etc/init等目录下的rc文件。各个目录下的rc文件具有不同的作用,一般来说按照如下划分:
/system/etc/init/ 用于系统本身,比如 SurfaceFlinger, MediaService, and logcatd。
/vendor/etc/init/ 用于SoC(系统级核心厂商,如高通), 为他们提供一些核心功能和服务。
/odm/etc/init/ 用于设备制造商(odm定制厂商,如华为、小米),为他们的传感器或外围设备提供一些核心功能和服务。
/product/etc/init/ 用于产品机型的配置。
对于很多系统级别的服务,在拥有自己独立的二进制执行文件时,也都拥有自己的rc启动文件。在Android.mk内可以通过LOCAL_INIT_RC指定rc启动文件,在Android.bp内也提供了一个init_rc配置项。
rc启动文件包含五个主要的部分,分别是:Actions,Commands,Services,Options,Imports。以下将分别介绍这几个部分。
Actions:从字面意义来看,这代表具体的行为。在rc启动文件中,Actions的部分都以on开头,其语法规则如下:
on <trigger> [&& <trigger>]*
<command>
<command>
<command>
这其中trigger代表具体的触发时机,trigger分为event triggers和property triggers。每一个Action可以存在多个trigger,但至少得有一个event trigger。如下面的例子: on property:a=b && property:c=d,这代表该Action将会在属性a与属性b相等iqe属性c与属性d相等时执行。
而所有的event triggers其实是有一个次序的,当前所有的次序如下:
early-init:cgroups配置完成
init:系统冷启动完成
charger:ro.bootmode == “charger”
late-init:ro.bootmode != “charger”
early-fs:Vold服务启动
fs:Vold启动完成,开始mount分区
post-fs:Configure anything dependent on early mount
last-fs:Mount partitions marked as latemounted.
post-fs-data:挂载data分区
zygote-start:启动zygote进程
early-boot:zygote启动完成
boot:启动完成
Commands:Commands指的是具体执行的命令。这些命令包括:chmod、chown、copy、enable、exec、exec_start、export、ifup、load_system_props、load_persist_props、mkdir、mount、restart、rmdir、setprop、symlink等等,以下列出了一些Commands的具体含义:
命令 | 描写叙述 |
---|---|
exec <path> [ <argument> ]* | 运行指定路径下的程序,并传递參数. |
export <name> <value> | 设置全局环境參数。此參数被设置后对全部进程都有效. |
ifup <interface> | 使指定的网络接口”上线”,相当激活指定的网络接口 |
import <filename> | 导入一个额外的init配置文件. |
hostname <name> | 设置主机名 |
chdir <directory> | 改变工作文件夹. |
chmod <octal-mode> <path> | 改变指定文件的读取权限. |
chown <owner> <group> <path> | 改变指定文件的拥有都和组名的属性. |
chroot <directory> | 改变进行的根文件夹. |
class_start <serviceclass> | 启动指定类属的全部服务,假设服务已经启动,则不再反复启动. |
class_stop <serviceclass> | 停止指定类属的所胡服务. |
domainname <name> | 设置域名 |
insmod <path> | 安装模块到指定路径. |
mkdir <path> [mode] [owner] [group] | 用指定參数创建一个文件夹,在默认情况下,创建的文件夹读取权限为755.username为root,组名为root. |
mount <type> <device> <dir> [ <mountoption> ]* | 类似于linux的mount指令 |
setkey TBD(To Be Determined), | 待定. |
setprop <name> <value> | 设置属性及相应的值. |
setrlimit <resource> <cur> <max> | 设置资源的rlimit(资源限制),不懂就百度一下rlimit |
start <service> | 假设指定的服务未启动,则启动它. |
stop <service> | 假设指定的服务当前正在执行。则停止它. |
symlink <target> <path> | 创建一个符号链接. |
sysclktz <mins_west_of_gmt> | 设置系统基准时间. |
trigger <event> Trigger an event. Used to queue an action from another action. | 这名话没有理解,望高手指点. |
write <path> <string> [ <string> ]* | 往指定的文件写字符串. |
关于这部分的细节,可以参考Android官方文档:https://android.googlesource.com/platform/system/core/+/master/init/README.md
Services:Service代指系统中运行的具体的服务。在rc文件中其语法结构为:
service <name><pathname> [ <argument> ]*
<option>
<option>
其中<name>指代该服务名称,<pathname>指向可执行文件所在的路径,[<argument>]为该可执行文件所能接受的参数,同时我们可以借助Options来对该服务进行一些额外的设定,如设定用户、用户组等,这里给出一个示例:
service evs_app /system/bin/evs_app
class hal
priority -20
user root
group root
disabled # will not automatically start with its class; must be explictly started.
在定义好服务后,如果未设定服务自启动,我们需要显示地通过start命令来启动。
Options:Options是用于修饰Service的,他们会影响init服务器在何时以及怎样去运行这些服务。一些常见的Options如下:
选项 | 描述 | |
---|---|---|
critical | 据设备相关的关键服务,如果在4分钟内,此服务重复启动了4次,那么设备将会重启进入还原模式。 | |
disabled | 服务不会自动运行,必须显式地通过服务器来启动。 | |
setenv | 设置环境变量 | |
socket [ [ ] ] | 在/dev/socket/下创建一个unix domain的socket,并传递创建的文件描述符fd给服务进程.其中type必须为dgram或stream,seqpacket. | 用户名和组名默认为0 |
user | 在执行此服务之前先切换用户名。当前默认为root. | |
group [ ]* | 类似于user,切换组名 | |
oneshot | 当此服务退出时不会自动重启. | |
class | 给服务指定一个类属,这样方便操作多个服务同时启动或停止.默认情况下为default. | |
onrestart | 当服务重启时执行一条指令, |
Imports:用于导入外部配置文件或者其他rc启动文件
以下为一个简单的rc启动文件,作为示例,大家可以对照着解析其中的内容:
#
on boot
export PATH /sbin:/system/sbin:/system/bin
export LD_LIBRARY_PATH /system/lib
mkdir /dev
mkdir /proc
mkdir /sys
mount tmpfs tmpfs /dev
mkdir /dev/pts
mkdir /dev/socket
mount devpts devpts /dev/pts
mount proc proc /proc
mount sysfs sysfs /sys
write /proc/cpu/alignment 4
ifup lo
hostname localhost
domainname localhost
mount yaffs2 mtd@system /system
mount yaffs2 mtd@userdata /data
import /system/etc/init.conf
class_start default
service adbd /sbin/adbd
user adb
group adb
service usbd /system/bin/usbd -r
user usbd
group usbd
socket usbd 666
service zygote /system/bin/app_process -Xzygote /system/bin --zygote
socket zygote 666
service runtime /system/bin/runtime
user system
group system
on device-added-/dev/compass
start akmd
on device-removed-/dev/compass
stop akmd
service akmd /sbin/akmd
disabled
user akmd
group akmd
好啦,以上就是本篇博客的全部内容,希望能够对大家有所帮助哦~