其中init进程是Linux系统中用户态的第一个进程
查看Init.cpp代码
int main(int argc, char** argv) {
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
if (!strcmp(basename(argv[0]), "watchdogd")) {
return watchdogd_main(argc, argv);
}
if (argc > 1 && !strcmp(argv[1], "subcontext")) {
InitKernelLogging(argv);
const BuiltinFunctionMap function_map;
return SubcontextMain(argc, argv, &function_map);
}
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
}
bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
if (is_first_stage) {
boot_clock::time_point start_time = boot_clock::now();
// Clear the umask.
umask(0);
clearenv();
setenv("PATH", _PATH_DEFPATH, 1);
// Get the basic filesystem setup we need put together in the initramdisk
// on / and then we'll let the rc file figure out the rest.
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));
// Don't expose the raw commandline to unprivileged processes.
chmod("/proc/cmdline", 0440);
gid_t groups[] = { AID_READPROC };
setgroups(arraysize(groups), groups);
mount("sysfs", "/sys", "sysfs", 0, NULL);
mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
if constexpr (WORLD_WRITABLE_KMSG) {
mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11));
}
mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
// Mount staging areas for devices managed by vold
// See storage config details at http://source.android.com/devices/storage/
mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
"mode=0755,uid=0,gid=1000");
// /mnt/vendor is used to mount vendor-specific partitions that can not be
// part of the vendor partition, e.g. because they are mounted read-write.
mkdir("/mnt/vendor", 0755);
// Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
// talk to the outside world...
InitKernelLogging(argv);
LOG(INFO) << "init first stage started!";
if (!DoFirstStageMount()) {
LOG(FATAL) << "Failed to mount required partitions early ...";
}
SetInitAvbVersionInRecovery();
// Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).
global_seccomp();
// Set up SELinux, loading the SELinux policy.
SelinuxSetupKernelLogging();
SelinuxInitialize();
// We're in the kernel domain, so re-exec init to transition to the init domain now
// that the SELinux policy has been loaded.
if (selinux_android_restorecon("/init", 0) == -1) {
PLOG(FATAL) << "restorecon failed of /init failed";
}
setenv("INIT_SECOND_STAGE", "true", 1);
static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);
char* path = argv[0];
char* args[] = { path, nullptr };
execv(path, args);
// execv() only returns if an error happened, in which case we
// panic and never fall through this conditional.
PLOG(FATAL) << "execv(\"" << path << "\") failed";
}
// At this point we're in the second stage of init.
InitKernelLogging(argv);
LOG(INFO) << "init second stage started!";
// Set up a session keyring that all processes will have access to. It
// will hold things like FBE encryption keys. No process should override
// its session keyring.
keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);
// Indicate that booting is in progress to background fw loaders, etc.
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
//初始化属性服务
property_init();
// If arguments are passed both on the command line and in DT,
// properties set in DT always have priority over the command-line ones.
process_kernel_dt();
process_kernel_cmdline();
// Propagate the kernel variables to internal variables
// used by init as well as the current required properties.
export_kernel_boot_props();
// Make the time that init started available for bootstat to log.
property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
// Set libavb version for Framework-only OTA match in Treble build.
const char* avb_version = getenv("INIT_AVB_VERSION");
if (avb_version) property_set("ro.boot.avb_version", avb_version);
// Clean up our environment.
unsetenv("INIT_SECOND_STAGE");
unsetenv("INIT_STARTED_AT");
unsetenv("INIT_SELINUX_TOOK");
unsetenv("INIT_AVB_VERSION");
// Now set up SELinux for second stage.
SelinuxSetupKernelLogging();
SelabelInitialize();
SelinuxRestoreContext();
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (epoll_fd == -1) {
PLOG(FATAL) << "epoll_create1 failed";
}
sigchld_handler_init();
if (!IsRebootCapable()) {
// If init does not have the CAP_SYS_BOOT capability, it is running in a container.
// In that case, receiving SIGTERM will cause the system to shut down.
InstallSigtermHandler();
}
property_load_boot_defaults();
export_oem_lock_status();
start_property_service();
set_usb_controller();
//设置解析命令函数映射表
const BuiltinFunctionMap function_map;
Action::set_function_map(&function_map);
subcontexts = InitializeSubcontexts();
ActionManager& am = ActionManager::GetInstance();
ServiceList& sm = ServiceList::GetInstance();
//解析init.rc
LoadBootScripts(am, sm);
// Turning this on and letting the INFO logging be discarded adds 0.2s to
// Nexus 9 boot time, so it's disabled by default.
if (false) DumpState();
//将early-init入队
am.QueueEventTrigger("early-init");
// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
// ... so that we can start queuing up actions that require stuff from /dev.
am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
am.QueueBuiltinAction(keychord_init_action, "keychord_init");
am.QueueBuiltinAction(console_init_action, "console_init");
// Trigger all the boot actions to get us started.
//将init入队
am.QueueEventTrigger("init");
// Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
// wasn't ready immediately after wait_for_coldboot_done
am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
// Don't mount filesystems or start core system services in charger mode.
std::string bootmode = GetProperty("ro.bootmode", "");
//当处于充电模式,则charger加入执行队列;否则late-init加入队列。
if (bootmode == "charger") {
am.QueueEventTrigger("charger");
} else {
am.QueueEventTrigger("late-init");
}
// Run all property triggers based on current state of the properties.
am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
while (true) {
// By default, sleep until something happens.
int epoll_timeout_ms = -1;
if (do_shutdown && !shutting_down) {
do_shutdown = false;
if (HandlePowerctlMessage(shutdown_command)) {
shutting_down = true;
}
}
if (!(waiting_for_prop || Service::is_exec_service_running())) {
//调用ActionManager按照入队顺序执行命令
am.ExecuteOneCommand();
}
if (!(waiting_for_prop || Service::is_exec_service_running())) {
if (!shutting_down) {
//重启服务
auto next_process_restart_time = RestartProcesses();
// If there's a process that needs restarting, wake up in time for that.
if (next_process_restart_time) {
epoll_timeout_ms = std::chrono::ceil<std::chrono::milliseconds>(
*next_process_restart_time - boot_clock::now())
.count();
if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
}
}
// If there's more work to do, wake up again immediately.
if (am.HasMoreCommands()) epoll_timeout_ms = 0;
}
epoll_event ev;
int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
if (nr == -1) {
PLOG(ERROR) << "epoll_wait failed";
} else if (nr == 1) {
((void (*)()) ev.data.ptr)();
}
}
return 0;
}
创建和挂载启动所需要的文件目录
初始化属性服务
设置解析命令函数映射表
在执行解析init.rc文件之前,将init.rc中的命令映射成相应的函数存放在function_map中,然后
通过set_function_map将映射关系存放在Action中作为成员属性
start 命令对应执行do_start函数
解析init.rc
LoadBootScripts方法中根据service、on、import创建不同类型的Parser,然后解析init.rc
ParseConfig最后调用到ParseData
当解析完init.rc后,会调用end_section(),把解析出的service放入一个Vector结构的列表 service_list
ServiceList
Zygote服务触发
${ro.zygote} 会被替换成 ro.zyogte 的属性值,这个是由不同的硬件厂商自己定制的,
有四个值,
zygote32:zygote 进程对应的执行程序是 app_process (纯 32bit 模式)
zygote64:zygote 进程对应的执行程序是 app_process64 (纯 64bit 模式)
zygote32_64:启动两个 zygote 进程 (名为 zygote 和 zygote_secondary),对应的执行程序分别
是 app_process32 (主模式)
zygote64_32: 启动两个 zygote 进程 (名为 zygote 和 zygote_secondary),对应的执行程序分别
是 app_process64 (主模式)、app_process32
查看Init.zygote64.rc中zygote服务的定义如下:
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc reserved_disk
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
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
zygote服务是何时启动的呢?
当处于充电模式,则charger加入执行队列;否则late-init加入队列。
加入执行队列后,会在init.cpp的main方法中调用am.ExecuteOneCommand();按照插入的顺序执行触发器对应的命令
1.未充电模式下的zygote服务的启动
查看init.rc
278on late-init
279 trigger early-fs
280
281 # Mount fstab in init.{$device}.rc by mount_all command. Optional parameter
282 # '--early' can be specified to skip entries with 'latemount'.
283 # /system and /vendor must be mounted by the end of the fs stage,
284 # while /data is optional.
285 trigger fs
286 trigger post-fs
287
288 # Mount fstab in init.{$device}.rc by mount_all with '--late' parameter
289 # to only mount entries with 'latemount'. This is needed if '--early' is
290 # specified in the previous mount_all command on the fs stage.
291 # With /system mounted and properties form /system + /factory available,
292 # some services can be started.
293 trigger late-fs
294
295 # Now we can mount /data. File encryption requires keymaster to decrypt
296 # /data, which in turn can only be loaded when system properties are present.
297 trigger post-fs-data
298
299 # Now we can start zygote for devices with file based encryption
300 trigger zygote-start
301
302 # Load persist properties and override properties (if enabled) from /data.
303 trigger load_persist_props_action
304
305 # Remove a file to wake up anything waiting for firmware.
306 trigger firmware_mounts_complete
307
308 trigger early-boot
309 trigger boot
由rc语法
Commands:
trigger < event >触发事件event,由一个action触发到另一个action队列
late-init的时候触发事件zygote-start:
558# It is recommended to put unnecessary data/ initialization from post-fs-data
559# to start-zygote in device's init.rc to unblock zygote start.
560on zygote-start && property:ro.crypto.state=unencrypted
561 # A/B update verifier that marks a successful boot.
562 exec_start update_verifier_nonencrypted
563 start netd
564 start zygote
565 start zygote_secondary
566
567on zygote-start && property:ro.crypto.state=unsupported
568 # A/B update verifier that marks a successful boot.
569 exec_start update_verifier_nonencrypted
570 start netd
571 start zygote
572 start zygote_secondary
573
574on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
575 # A/B update verifier that marks a successful boot.
576 exec_start update_verifier_nonencrypted
577 start netd
578 start zygote
579 start zygote_secondary
由rc语法
Actions:
Actions由一行行命令组成. trigger用来决定什么时候触发这些命令,当一个事件满足trigger的触发条件时,
这个action就会被加入到处理队列中(除非队列中已经存在)队列中的action按顺序取出执行,action中的命令按顺序执行. 这些命令主要用来执行一些操作(设备创建/销毁,属性设置,进程重启)
Actions的格式如下:
on <trigger> [&& <trigger>]*
<command>
<command>
<command>
Triggers:
Triggers 是个字符串,当一些事件发生满足该条件时,一些actions就会被执行
Triggers分为事件Trigger和属性Trigger
事件Trigger由trigger 命令或QueueEventTrigger方法触发.它的格式是个简单的字符串,比如’boot’ 或 ‘late-init’.
属性Trigger是在属性被设置或发生改变时触发. 格式是’property:< name>=< value>‘或’property:< name>=*’,它会在init初始化设置属性的时候触发.
属性Trigger定义的Action可能有多种触发方式,但是事件Trigger定义的Action可能只有一种触发方式
比如:
on boot && property:a=b 定义了action的触发条件是,boot Trigger触发,并且属性a的值等于b
on property:a=b && property:c=d 这个定义有三种触发方式:
- 在初始化时,属性a=b,属性c=d.
- 在属性c=d的情况下,属性a被改为b.
- A在属性a=b的情况下,属性c被改为d.
Commands:
start < service>启动一个未运行的service
根据rc语法,
在on late-init中,而且要满足
property:ro.crypto.state=unencrypted
property:ro.crypto.state=unencrypted 或者
property:ro.crypto.state=encrypted且 property:ro.crypto.type=file时
触发执行启动zygote 服务的命令
start zygote
再来看一下zygote 服务的定义
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc reserved_disk
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
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
class < name > [ < name >* ]
为Service指定class名字. 同一个class名字的Service会被一起启动或退出,默认值是"default",第二个name可以不设置,用于service组.
根据rc语法 ,这里给zygote服务指定了一个class名字 main
这个zygote 进程对应的执行程序是 app_process64
app_process程序的代码在app_main.cpp
在“设置解析命令函数映射表”小节中介绍了start 命令对应执行do_start函数:
接着调用Start()方法
Start()方法调用ExpandArgsAndExecv(args_)方法
最终通过 execv(c_strings[0], c_strings.data()),进入App_main.cpp的main()函数
2.充电模式下不会触发zygote服务启动,这一部分是Android关机充电流程,这里先不做分析
查看init.rc
680on nonencrypted
681 class_start main
682 class_start late_start
683
684on property:sys.init_log_level=*
685 loglevel ${sys.init_log_level}
686
687on charger
688 class_start charger
689
690on property:vold.decrypt=trigger_reset_main
691 class_reset main
692
693on property:vold.decrypt=trigger_load_persist_props
694 load_persist_props
695 start logd
696 start logd-reinit
697
698on property:vold.decrypt=trigger_post_fs_data
699 trigger post-fs-data
700 trigger zygote-start
701
702on property:vold.decrypt=trigger_restart_min_framework
703 # A/B update verifier that marks a successful boot.
704 exec_start update_verifier
705 class_start main
706
707on property:vold.decrypt=trigger_restart_framework
708 stop surfaceflinger
709 start surfaceflinger
710 # A/B update verifier that marks a successful boot.
711 exec_start update_verifier
712 class_start main
713 class_start late_start
on charger 触发的时候会class_start charger,不会 start zygote。
服务重启
当init子进程退出时,会产生SIGCHLD信号,并发送给init进程,通过socket套接字传递数据,调用到wait_for_one_process()方法,根据是否是oneshot,来决定是重启子进程,还是放弃启动。
servicemanager进程被杀;
(onresart)surfaceflinger进程被杀;
(onresart)Zygote进程自己被杀;
(oneshot=false)system_server进程被杀;
都会触发Zygote重启
总结
init进程主要的任务
- 创建和挂载启动所需要的文件目录
- 初始化和启动属性服务
- 解析rc文件,启动相应属性服务进程(包括启动zygote进程)
- 进入无限循环,
检查 event_queue是否为空,不为空的话执行相应的事件
检查是否有需要重启的进程,有的话重启进程
进入epoll_waite等待状态,直到收到系统属性变化事件(property_set改变属性值),或收到子进程的SIGCHLD信号,再或者keychord键盘输入事件,则会堆出等待状态,执行相应的回调函数。
zygote 触发流程
当处于未充电模式
总结和学习中,如有错误欢迎指正
参考相关资料
http://gityuan.com/2016/02/05/android-init/
关于充电模式 《Android init进程中鲜为人知的charger mode 模式》
https://blog.csdn.net/kaixinbingju/article/details/9250663