源码Android10
init 概述
init进程是Linux系统中用户空间的第一个进程,进程号固定为1。启动代码在 system/core/init/main.cpp
中
int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
__asan_set_error_report_callback(AsanReportCallback);
#endif
if (!strcmp(basename(argv[0]), "ueventd")) {//不清楚何时调用
return ueventd_main(argc, argv);
}
if (argc > 1) {
if (!strcmp(argv[1], "subcontext")) {//不清楚何时调用
android::base::InitLogging(argv, &android::base::KernelLogger);
const BuiltinFunctionMap function_map;
return SubcontextMain(argc, argv, &function_map);
}
if (!strcmp(argv[1], "selinux_setup")) {
return SetupSelinux(argv);
}
if (!strcmp(argv[1], "second_stage")) {
return SecondStageMain(argc, argv);
}
}
return FirstStageMain(argc, argv);
}
已知调用顺序:FirstStageMain --> SetupSelinux --> SecondStageMain
- FirstStageMain : 挂载及创建基本的文件系统,并设置合适的访问权限; 关闭默认控制台输出,并初始化内核级log; 挂载 system、cache、data 等系统分区
- SetupSelinux : 设置SELinux安全策略
- SecondStageMain : 核心步骤,下面详细解释
SecondStageMain
SecondStageMain
方法在 system/core/init/init.cpp
中,下面只列出了核心代码
int SecondStageMain(int argc, char** argv) {
...
//初始化属性服务,并从指定文件读取属性
property_init();
...
//epoll 中注册signalfd,主要是为了创建handler处理子进程终止信号(SIGCHLD)
InstallSignalFdHandler(&epoll);
...
//解析init.rc文件,文件在 system/core/rootdir 目录下
LoadBootScripts(am, sm);
...
//执行rc文件中触发器为on early-init的语句
am.QueueEventTrigger("early-init");
...
//执行rc文件中触发器为on init的语句
am.QueueEventTrigger("init");
...
// 当处于充电模式,则charger加入执行队列;否则late-init加入队列。
std::string bootmode = GetProperty("ro.bootmode", "");
if (bootmode == "charger") {
am.QueueEventTrigger("charger");
} else {
am.QueueEventTrigger("late-init");
}
...
while (true) {
// By default, sleep until something happens.
auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
if (do_shutdown && !shutting_down) {//关机重启
do_shutdown = false;
if (HandlePowerctlMessage(shutdown_command)) {
shutting_down = true;
}
}
if (!(waiting_for_prop || Service::is_exec_service_running())) {//?
am.ExecuteOneCommand();
}
if (!(waiting_for_prop || Service::is_exec_service_running())) {//重启进程
if (!shutting_down) {
auto next_process_action_time = HandleProcessActions();
// If there's a process that needs restarting, wake up in time for that.
if (next_process_action_time) {
epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
*next_process_action_time - boot_clock::now());
if (*epoll_timeout < 0ms) epoll_timeout = 0ms;
}
}
// If there's more work to do, wake up again immediately.
if (am.HasMoreCommands()) epoll_timeout = 0ms;
}
if (auto result = epoll.Wait(epoll_timeout); !result) {//循环等待事件发生
LOG(ERROR) << result.error();
}
}
return 0;
}
属性服务
一般而言,系统或者某些应用程序会把自己的一些属性存储在注册表中(注册表可以存储一些类似key/value的键值对),即使系统重启或者应用程序重启,它还能根据之前在注册表中设置的属性,进行相应的初始化工作。Android平台也提供了类似的机制,称为属性服务。应用程序可以通过这个属性机制查询或者设置属性。
property_init()
在 system/core/init/property_service.cpp
文件中
信号处理
在Linux内核中,如父进程不等待子进程的结束直接退出,会导致子进程在结束后变成僵尸进程,占用系统资源。为此,init进程专门安装了SIGCHLD信号接收器,当某些子进程退出时发现其父进程已经退出,则会向init进程发送SIGCHLD信号,init进程调用回调方法handle_signal()来回收僵尸子进程。
init.rc
nit.rc文件在 system/core/rootdir 目录下
Action
Action: 通过触发器trigger,即以on开头的语句来决定执行相应的service的时机,具体有如下时机:
on early-init; 在初始化早期阶段触发;
on init; 在初始化阶段触发;
on late-init; 在初始化晚期阶段触发;
on boot/charger: 当系统启动/充电时触发,还包含其他情况,此处不一一列举;
on property:<key>=<value>: 当属性值满足条件时触发;
Service
服务Service,以 service开头,由init进程启动,一般运行在init的一个子进程,所以启动service前需要判断对应的可执行文件是否存在。init生成的子进程,定义在rc文件,其中每一个service在启动时会通过fork方式生成子进程。
例如: service servicemanager /system/bin/servicemanager代表的是服务名为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级别
trigger command :触发命令
Options
Options是Service的可选项,与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。
参考
http://gityuan.com/2016/02/05/android-init/
https://www.imgeek.org/article/825358229
https://juejin.cn/post/6998441504364560420/