经过前面的开篇介绍,我们对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:
它主要包含四种类型语句:Action、Commands、Services、Options
Action(动作): 通过trigger,即以 on开头的语句,决定何时执行相应的service。
- on early-init; 在初始化早期阶段触发;
- on init; 在初始化阶段触发;
- on late-init; 在初始化晚期阶段触发;
- on boot/charger: 当系统启动/充电时触发,还包含其他情况,此处不一一列举;
- on property:<key>=<value>: 当属性值满足条件时触发;
启动顺序:on early-init -> init -> late-init -> boot
Service(服务):是一个程序,他在初始化时启动,并在退出时重启(可选),由init进程启动,一般运行于另外一个init的子进程,所以启动service前需要判断对应的可执行文件是否存在。init生成的子进程,定义在rc文件,其中每一个service,在启动时会通过fork方式生成子进程。
例: service servicemanager(服务名 ) /system/bin/servicemanager ( 路径)
Command(命令): 要执行的命令
常用的命令:
- class_start <service_class_name>: 启动属于同一个class的所有服务;
- start <service_name>: 启动指定的服务,若已启动则跳过;
- stop <service_name>: 停止正在运行的服务
- setprop <name> <value>:设置属性值
- mkdir <path>:创建指定目录
- symlink <target> <sym_link>: 创建连接到<target>的<sym_link>符号链接;
- write <path> <string>: 向文件path中写入字符串;
- exec: fork并执行,会阻塞init进程直到程序完毕;
- exprot <name> <name>:设定环境变量;
- loglevel <level>:设置log级别
Option(选项):Options是Services的可选项,与service配合使用
- disabled: 不随class自动启动,只有根据service名才启动;
- oneshot: service退出后不再重启;
- user/group: 设置执行服务的用户/用户组,默认都是root;
- class:设置所属的类名,当所属类启动/退出时,服务也启动/停止,默认为default;
- onrestart:当服务重启时执行相应命令;
- socket: 创建名为/dev/socket/<name>的socket
- critical: 在规定时间内该service不断重启,则系统会重启并进入恢复模式
default: 意味着disabled=false,oneshot=false,critical=false。
Action与Option配合使用:
on <trigger>
<command>
<command>
举例:
on boot
ifup lo
hostname localhost
domainname localdomain
class_start default
Service与Command配合使用:
service <name> <pathname> [ <argument> ]*
<option>
<option>
举例:
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共同创建的。
流程如下:
app_main.cpp的main()方法中,最终通过Androidrumtime来启动zygote进程。
2.3 服务重启
init进程会启动很多native的service,这些service如果不是oneshot的,当service出现异常挂掉后,init需要将其重新启动起来:
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
网友评论