Android FrameWork详细教程—第一个启动的程序--init 与 Zygote

第一个启动的程序–init

不管Java还是C++运行一个程序都是以main方法作为入口。所以我们先看看init.cpp的main函数.

目录:/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);//在这里创建和挂载了启动所需要的目录信息包含tmpfs、devpts、proc、sysfs、selinuxfs文件系统。。
}

在Main函数,分了几个阶段,首先第一步是FirstStageMain,我们看看他做了什么?

目录:/system/core/init/first_stage_init.cpp

具体代码:

int FirstStageMain(int argc, char** argv) {
   
    if (REBOOT_BOOTLOADER_ON_PANIC) {
   
        InstallRebootSignalHandlers();
    }

    boot_clock::time_point start_time = boot_clock::now();

    std::vector<std::pair<std::string, int>> errors;
#define CHECKCALL(x) \
    if ((x) != 0) errors.emplace_back(#x " failed", errno);

    // Clear the umask.
    umask(0);

    CHECKCALL(clearenv());
    CHECKCALL(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.
    CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));//挂载了tmpfs
    CHECKCALL(mkdir("/dev/pts", 0755));//创建pts目录并且赋予0755的权限
    CHECKCALL(mkdir("/dev/socket", 0755));//创建socket目录并且赋予0755的权限
    CHECKCALL(mkdir("/dev/dm-user", 0755));//创建dm-user目录并且赋予0755的权限
    CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));//挂载devpts
#define MAKE_STR(x) __STRING(x)
    CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)));//挂载proc文件系统
#undef MAKE_STR
    // Don't expose the raw commandline to unprivileged processes.
    CHECKCALL(chmod("/proc/cmdline", 0440));
    std::string cmdline;
    android::base::ReadFileToString("/proc/cmdline", &cmdline);
    // Don't expose the raw bootconfig to unprivileged processes.
    chmod("/proc/bootconfig", 0440);
    std::string bootconfig;
    android::base::ReadFileToString("/proc/bootconfig", &bootconfig);
    gid_t groups[] = {
   AID_READPROC};
    CHECKCALL(setgroups(arraysize(groups), groups));
    CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));//挂载sysfs
    CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL));//挂载selinxfs

    CHECKCALL(mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11)));

    if constexpr (WORLD_WRITABLE_KMSG) {
   
        CHECKCALL(mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11)));
    }

    CHECKCALL(mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8)));
    CHECKCALL(mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9)));

    CHECKCALL(mknod("/dev/ptmx", S_IFCHR | 0666, makedev(5, 2)));
    CHECKCALL(mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3)));

    CHECKCALL(mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                    "mode=0755,uid=0,gid=1000"));
    CHECKCALL(mkdir("/mnt/vendor", 0755));
    CHECKCALL(mkdir("/mnt/product", 0755));
    CHECKCALL(mount("tmpfs", "/debug_ramdisk", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                    "mode=0755,uid=0,gid=0"));
    CHECKCALL(mount("tmpfs", kSecondStageRes, "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                    "mode=0755,uid=0,gid=0"))
#undef CHECKCALL

    SetStdioToDevNull(argv);
    InitKernelLogging(argv);


    const char* path = "/system/bin/init";
    const char* args[] = {
   path, "selinux_setup", nullptr};
    auto fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
    dup2(fd, STDOUT_FILENO);
    dup2(fd, STDERR_FILENO);
    close(fd);
    execv(path, const_cast<char**>(args));

    // execv() only returns if an error happened, in which case we
    // panic and never fall through this conditional.
    PLOG(FATAL) << "execv(\"" << path << "\") failed";

    return 1;
}

原来init进程的第一个阶段主要是挂载了tmpfs、devpts、proc、sysfs和selinux 文件系统,也就是说android系统启动就挂载了,关闭就消失了。

其中文件系统:

1.tmpfs:虚拟文件系统,他把所有的文件都存在虚拟内存中。tmpfs速度很快,毕竟他是驻留在RAM中。但是由于驻留在RAM中,所以断电之后文件内容不会被保存。

2.devpts:管理远程虚拟终端文件设备,挂接点是/dev/pts。pty的主复合设备/dev/ptmx被打开,就会在/dev/pts下创建pty设备文件。

3.proc:非常重要的虚拟文件系统,,通过它我们可以获得系统信息,同时也能够在运行时修改特定的内核参数。

4.sysfs:和proc类似,把连接在系统上的设备和总线组织成一个分级的文件,使得它们可以在用户空间存取。

5.selinux:对系统中每一个对象都生成一个安全上下文,每个对象访问系统资源都需要进行上下文审查。

再挂在完成之后,又返回了init 启动了selinux_setup。

int SetupSelinux(char** argv) {
   
    SetStdioToDevNull(argv);
    InitKernelLogging(argv);

    if (REBOOT_BOOTLOADER_ON_PANIC) {
   
        InstallRebootSignalHandlers();
    }

    boot_clock::time_point start_time = boot_clock::now();

    MountMissingSystemPartitions();

    SelinuxSetupKernelLogging();

    LOG(INFO) << "Opening SELinux policy";

    PrepareApexSepolicy();

    // Read the policy before potentially killing snapuserd.
    std::string policy;
    ReadPolicy(&policy);
    CleanupApexSepolicy();

    auto snapuserd_helper = SnapuserdSelinuxHelper::CreateIfNeeded();
    if (snapuserd_helper) {
   
        snapuserd_helper->StartTransition();
    }

    LoadSelinuxPolicy(policy);

    if (snapuserd_helper) {
   
        // Before enforcing, finish the pending snapuserd transition.
        snapuserd_helper->FinishTransition();
        snapuserd_helper = nullptr;
    }

    if (selinux_android_restorecon("/dev/selinux/", SELINUX_ANDROID_RESTORECON_RECURSE) == -1) {
   
        PLOG(FATAL) << "restorecon failed of /dev/selinux failed";
    }

    SelinuxSetEnforcement();


    if (selinux_android_restorecon("/system/bin/init", 0) == -1) {
   
        PLOG(FATAL) << "restorecon failed of /system/bin/init failed";
    }

    setenv(kEnvSelinuxStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(), 1);

    const char* path = "/system/bin/init";
    const char* args[] = {
   path, "second_stage", nullptr};
    execv(path, const_cast<char**>(args));//执行second_stage

    PLOG(FATAL) << "execv(\"" << path << "\") failed";

    return 1;
}

selinux是安全权限相关,感兴趣的大家可以自行学习研究。 在执行完成之后回到init 执行了second_stage。

文件目录:system/core/init/init.cpp 在线地址:


int SecondStageMain(int argc, char** argv) {
   
    if (REBOOT_BOOTLOADER_ON_PANIC) {
   
        InstallRebootSignalHandlers();
    }
    SetStdioToDevNull(argv);
    InitKernelLogging(argv);
    LOG(INFO) << "init second stage started!";
    if (auto result = WriteFile("/proc/1/oom_score_adj", "-1000"); !result) {
   
        LOG(ERROR) << "Unable to write -1000 to /proc/1/oom_score_adj: " << result.error();
    }
    GlobalSeccomp();
    keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);
    close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
    property_init();//初始化属性服务
    process_kernel_dt();
    process_kernel_cmdline();
    export_kernel_boot_props();
    property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
    property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
    const char* avb_version = getenv("INIT_AVB_VERSION");
    if (avb_version) property_set("ro.boot.avb_version", avb_version);
    const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
    if (force_debuggable_env && AvbHandle::IsDeviceUnlocked()) {
   
        load_debug_prop = "true"s == force_debuggable_env;
    }
    unsetenv("INIT_STARTED_AT");
    unsetenv("INIT_SELINUX_TOOK");
    unsetenv("INIT_AVB_VERSION");
    unsetenv("INIT_FORCE_DEBUGGABLE");
    SelinuxSetupKernelLogging();
    SelabelInitialize();
    SelinuxRestoreContext();
    //创建Epoll
    Epoll epoll;
    if (auto result = epoll.Open(); !result) {
   
        PLOG(FATAL) << result.error();
    }
    //创建Handler,监听子进程的信号,如果子进程异常退出,init会调用对应的处理函数来进行处理。
    InstallSignalFdHandler(&epoll);
    property_load_boot_defaults(load_debug_prop);
    UmountDebugRamdisk();
    fs_mgr_vendor_overlay_mount_all();
    export_oem_lock_status();
    //开启属性服务
    StartPropertyService(&epoll);
    MountHandler mount_handler(&epoll);
    set_usb_controller();
    const BuiltinFunctionMap function_map;
    Action::set_function_map(&function_map);
    if (!SetupMountNamespaces()) {
   
        PLOG(FATAL) << "SetupMountNamespaces failed";
    }
    subcontexts = InitializeSubcontexts();
    ActionManager& am = ActionManager::GetInstance();
    ServiceList& sm = ServiceList::GetInstance();
    //加载配置脚本文件 init.rc
    LoadBootScripts(am, sm);
    if (false) DumpState();
    // Make the GSI status available before scripts start running.
    if (android::gsi::IsGsiRunning()) {
   
        property_set("ro.gsid.image_running", "1");
    } else {
   
        property_set("ro.gsid.image_running", "0");
    }
    am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
    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");
    Keychords keychords;
    am.QueueBuiltinAction(
        [&epoll, &keychords](const BuiltinArguments& args) -> Result<Success> {
   
            for (const auto& svc : ServiceList::GetInstance()) {
   
                keychords.Register(svc->keycodes());
            }
            keychords.Start(&epoll, HandleKeychord);
            return Success();
        },
        "KeychordInit");
    am.QueueBuiltinAction(console_init_action, "console_init");
    // Trigger all the boot actions to get us started.
    am.QueueEventTrigger("init");
    // Starting the BoringSSL self test, for NIAP certification compliance.
    am.QueueBuiltinAction(StartBoringSslSelfTest, "StartBoringSslSelfTest");
    // 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");
    // Initialize binder before bringing up other system services
    am.QueueBuiltinAction(InitBinder, "InitBinder");
    // Don't mount filesystems or start core system services in charger mode.
    std::string bootmode = GetProperty("ro.bootmode", "");
    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.
        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;
}

代码比较多,我们只需要看关键的几点 我都加了注释: 1.property_init。属性服务类似于Windows平台上的注册表管理器,主要记录一些用户、软件的使用信息。当系统启动、重启 都是根据之前的记录进行对应的初始化。

2.创建Handler,监听子进程的信号,如果子进程异常退出,init会调用对应的处理函数来进行处理。

3.创建Epoll。

4.开启属性服务。

5.解析init.rc配置文件。

顺便提一下,Epoll面试大家遇见的也比较多。后边我会解释Epoll。

下面我们分别看一下 这几个函数都做了什么。

1.属性服务的初始化 ——> property_init

void property_init() {
   
    mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
    CreateSerializedPropertyInfo();//创建了配置的info
    if (__system_property_area_init()) {
   //初始化property的内存区域。
        LOG(FATAL) << "Failed to initialize property area";
    }
    if (!property_info_area.LoadDefaultPath()) {
   
        LOG(FATAL) << "Failed to load serialized property info file";
    }
}

总结:创建了Property的info信息。并且初始化了property的内存区域。

2.开启属性服务 -->StartPropertyService

文件目录:/system/core/init/property_service.cpp

void StartPropertyService(Epoll* epoll) {
   
    selinux_callback cb;
    cb.func_audit = SelinuxAuditCallback;
    //设置selinux的callback
    selinux_set_callback(SELINUX_CB_AUDIT, cb);

    property_set("ro.property_service.version", "2");
     //创建属性的非阻塞式socket
    property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                   false, 0666, 0, 0, nullptr);
    if (property_set_fd == -1) {
   
        PLOG(FATAL) << "start_property_service socket creation failed";
    }
    //listen对property_set_fd进行监听,最多可以同时为8个链接提供服务。
    listen(property_set_fd, 8);
     //epoll 注册Handler,监听property_set_fd,当有更新的时候会调用handle_property_set_fd来进行处理。
    if (auto result = epoll->RegisterHandler(property_set_fd, handle_property_set_fd); !result) {
   
        PLOG(FATAL) << result.error(
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值