美文网首页
深入了解Android读书笔记——深入理解init

深入了解Android读书笔记——深入理解init

作者: 新一代螺丝工 | 来源:发表于2022-09-27 22:55 被阅读0次

源码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/

相关文章

网友评论

      本文标题:深入了解Android读书笔记——深入理解init

      本文链接:https://www.haomeiwen.com/subject/dxmqartx.html