Android源码分析挖掘-开天辟地init进程

序言

PC启动一般会通过BIOS或者EFI引导程序启动,Android一般作为移动设备,没有PC的BIOS或者EFI,取而代之的是BootLoader。

BootLoader

按下电源键CPU上电完成后,会从固定地址加载一段程序,就是BootLoader,不通的CPU可能地址段会有差异,BootLoader是一段引导程序,常见的就是U-boot。

U-boot程序启动后,一般会先检测是否同时按下了触发U-boot功能的按键,比如进入Recovery模式等, 这些按键一般是在U-boot中事先编码好的。

如果没有按下这些按键,U-boot会从nand flash中装载linux内核,装载的地址也是在编译uboot时预定好的。linux内核启动后,会创建第一个进程:idle。

idle进程

idle进程是linux进程启动后创建的第一个进程,其pid=0,idle进程被创建后会创建init进程和kthreadd进程,然后idle会在cpu没有任务时进行空转。

kthreadd进程

kthreadd被创建后,其pid=2,运行在内核空间,负责所有内核线程的调度和管理。

init进程

init进程是linux系统的第一个用户进程,其pid=1,是系统所有用户进程的根进程,其源码在/system/core/init/main.cpp中,以main方法为入口:

using namespace android::init;

int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#endif
    // Boost prio which will be restored later
    setpriority(PRIO_PROCESS, 0, -20);
    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 = GetBuiltinFunctionMap();

            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);
}

默认启动无参数,会进入init的第一阶段,会调用FirstStageMain函数,通过命令搜索FirstStageMain函数所在文件:

//输入以下搜索命令,然后点击Enter
grep FirstStageMain ./ -rn

搜索结果如下:

./first_stage_main.cpp:20:    return android::init::FirstStageMain(argc, argv);
./first_stage_init.h:22:int FirstStageMain(int argc, char** argv);
./main.cpp:78:    return FirstStageMain(argc, argv);
./first_stage_init.cpp:183:int FirstStageMain(int argc, char** argv) {

可以知道是在./first_stage_init.cpp第183行,输入如下命令定位到函数所在行

vi ./first_stage_init.cpp +183

FirstStageMain函数中可以看到,会先对文件系统进行一系列的权限设定,然后通过执行execv再次调用init,传入参数selinux_setup,进入到init的第二阶段

int FirstStageMain(int argc, char** argv) {
    ...

    // Clear the umask.
    //权限掩码设置为0,则都是111,其他授权时最终的规则就是:(xxx & ~掩码 = 最终权限)
    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"));
    CHECKCALL(mkdir("/dev/pts", 0755));
    CHECKCALL(mkdir("/dev/socket", 0755));
    CHECKCALL(mkdir("/dev/dm-user", 0755));
    CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
#define MAKE_STR(x) __STRING(x)
    CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)));
#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));
    CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL));

    ...

    //通过execv再次执行init,传入参数selinux_setup,进入到init的第二阶段
    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(args));
}

再次回看/system/core/init/main.cpp源码,由于本次传入的参数是selinux_setup,结合代码可以看到,会进入到SetupSelinux这个函数中

using namespace android::init;

int main(int argc, char** argv) {
    ...
    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();

            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);
        }
    }
    ...
}

通过命令搜索

grep SetupSelinux ./ -rn

搜索结果如下

./selinux.cpp:730:int SetupSelinux(char** argv) {
./main.cpp:70:            return SetupSelinux(argv);
./selinux.h:23:int SetupSelinux(char** argv);

使用命令定位到行

vi ./selinux.cpp +730

代码如下,此阶段主要是启动Selinux安全机制,初始化selinux,加载SELinux规则和配置SELinux相关log输出,然后通过执行execv再次调用init,传入参数selinux_setup,进入到init的第三阶段

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";
    ...
    LoadSelinuxPolicy(policy);
    if (snapuserd_helper) {
        snapuserd_helper->FinishTransition();
        snapuserd_helper = nullptr;
    }
    SelinuxSetEnforcement();
    setenv(kEnvSelinuxStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(), 1);

    //通过execv再次执行init,传入参数second_stage,进入到init的第三阶段
    const char* path = "/system/bin/init";
    const char* args[] = {path, "second_stage", nullptr};
    execv(path, const_cast(args));
    ...
    return 1;
}

再次回看/system/core/init/main.cpp源码,本次传入的参数是second_stage,结合代码可以看到,会进入到SecondStageMain这个函数中,同样的方式,搜索

grep SecondStageMain ./ -rn

搜索结果

./init.h:47:int SecondStageMain(int argc, char** argv);
./main.cpp:74:            return SecondStageMain(argc, argv);
./init.cpp:742:int SecondStageMain(int argc, char** argv) {

使用命令定位到行

vi ./init.cpp +742

代码如下,此阶段主要是初始化了一些属性和解析init.rc,以及守护服务

int SecondStageMain(int argc, char** argv) {
    ...
    // Indicate that booting is in progress to background fw loaders, etc.
    //设置启动中标记
    close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
    ...
    //初始化系统属性
    PropertyInit();
    ...
    // Mount extra filesystems required during second stage init
    //挂载额外的文件系统
    MountExtraFilesystems();
    // Now set up SELinux for second stage.
    //设置SElinux相关
    SelinuxSetupKernelLogging();
    SelabelInitialize();
    SelinuxRestoreContext();
    //使用epoll注册信号处理函数,守护进程服务
    Epoll epoll;
    if (auto result = epoll.Open(); !result.ok()) {
        PLOG(FATAL) << result.error();
    }
    InstallSignalFdHandler(&epoll);
    InstallInitNotifier(&epoll);
    //启动系统属性服务
    StartPropertyService(&property_fd);
    ...
    //设置commands指令对应的函数map,用于在后面解析init.rc文件中的指令查找
    const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
    Action::set_function_map(&function_map);
    ...
    //解析init.rc脚本
    ActionManager& am = ActionManager::GetInstance();
    ServiceList& sm = ServiceList::GetInstance();
    LoadBootScripts(am, sm);
    ...
    while (true) {
        // By default, sleep until something happens.
        auto epoll_timeout = std::optional{};
        ...
        //执行从init.rc脚本解析出来的每条指令
        if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
            am.ExecuteOneCommand();
        }
        ...
        if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
            // If there's more work to do, wake up again immediately.
            if (am.HasMoreCommands()) epoll_timeout = 0ms;
        }
        auto pending_functions = epoll.Wait(epoll_timeout);
        if (!pending_functions.ok()) {
            LOG(ERROR) << pending_functions.error();
        } else if (!pending_functions->empty()) {
            // We always reap children before responding to the other pending functions. This is to
            // prevent a race where other daemons see that a service has exited and ask init to
            // start it again via ctl.start before init has reaped it.
            //子进程退出后的处理
            ReapAnyOutstandingChildren();
            for (const auto& function : *pending_functions) {
                (*function)();
            }
        }
        ...
    }
    return 0;
}

其他的可先不做分析,重点分析一下两点:

1.先看一下GetBuiltinFunctionMap函数做了什么,源码在/system/core/init/builtins.cpp,这个函数保存了指令与函数的对应关系,当发起key的调用时,会调用value对应的函数。


// Builtin-function-map start
const BuiltinFunctionMap& GetBuiltinFunctionMap() {
    constexpr std::size_t kMax = std::numeric_limits::max();
    // clang-format off
    static const BuiltinFunctionMap builtin_functions = {
        {"bootchart",               {1,     1,    {false,  do_bootchart}}},
        {"chmod",                   {2,     2,    {true,   do_chmod}}},
        {"chown",                   {2,     3,    {true,   do_chown}}},
        {"class_reset",             {1,     1,    {false,  do_class_reset}}},
        {"class_reset_post_data",   {1,     1,    {false,  do_class_reset_post_data}}},
        {"class_restart",           {1,     1,    {false,  do_class_restart}}},
        {"class_start",             {1,     1,    {false,  do_class_start}}},
        {"class_start_post_data",   {1,     1,    {false,  do_class_start_post_data}}},
        {"class_stop",              {1,     1,    {false,  do_class_stop}}},
        {"copy",                    {2,     2,    {true,   do_copy}}},
        {"copy_per_line",           {2,     2,    {true,   do_copy_per_line}}},
        {"domainname",              {1,     1,    {true,   do_domainname}}},
        {"enable",                  {1,     1,    {false,  do_enable}}},
        {"exec",                    {1,     kMax, {false,  do_exec}}},
        {"exec_background",         {1,     kMax, {false,  do_exec_background}}},
        {"exec_start",              {1,     1,    {false,  do_exec_start}}},
        {"export",                  {2,     2,    {false,  do_export}}},
        {"hostname",                {1,     1,    {true,   do_hostname}}},
        {"ifup",                    {1,     1,    {true,   do_ifup}}},
        {"init_user0",              {0,     0,    {false,  do_init_user0}}},
        {"insmod",                  {1,     kMax, {true,   do_insmod}}},
        {"installkey",              {1,     1,    {false,  do_installkey}}},
        {"interface_restart",       {1,     1,    {false,  do_interface_restart}}},
        {"interface_start",         {1,     1,    {false,  do_interface_start}}},
        {"interface_stop",          {1,     1,    {false,  do_interface_stop}}},
        {"load_exports",            {1,     1,    {false,  do_load_exports}}},
        {"load_persist_props",      {0,     0,    {false,  do_load_persist_props}}},
        {"load_system_props",       {0,     0,    {false,  do_load_system_props}}},
        {"loglevel",                {1,     1,    {false,  do_loglevel}}},
        {"mark_post_data",          {0,     0,    {false,  do_mark_post_data}}},
        {"mkdir",                   {1,     6,    {true,   do_mkdir}}},
        // TODO: Do mount operations in vendor_init.
        // mount_all is currently too complex to run in vendor_init as it queues action triggers,
        // imports rc scripts, etc.  It should be simplified and run in vendor_init context.
        // mount and umount are run in the same context as mount_all for symmetry.
        {"mount_all",               {0,     kMax, {false,  do_mount_all}}},
        {"mount",                   {3,     kMax, {false,  do_mount}}},
        {"perform_apex_config",     {0,     0,    {false,  do_perform_apex_config}}},
        {"umount",                  {1,     1,    {false,  do_umount}}},
        {"umount_all",              {0,     1,    {false,  do_umount_all}}},
        {"update_linker_config",    {0,     0,    {false,  do_update_linker_config}}},
        {"readahead",               {1,     2,    {true,   do_readahead}}},
        {"remount_userdata",        {0,     0,    {false,  do_remount_userdata}}},
        {"restart",                 {1,     1,    {false,  do_restart}}},
        {"restorecon",              {1,     kMax, {true,   do_restorecon}}},
        {"restorecon_recursive",    {1,     kMax, {true,   do_restorecon_recursive}}},
        {"rm",                      {1,     1,    {true,   do_rm}}},
        {"rmdir",                   {1,     1,    {true,   do_rmdir}}},
        {"setprop",                 {2,     2,    {true,   do_setprop}}},
        {"setrlimit",               {3,     3,    {false,  do_setrlimit}}},
        {"start",                   {1,     1,    {false,  do_start}}},
        {"stop",                    {1,     1,    {false,  do_stop}}},
        {"swapon_all",              {0,     1,    {false,  do_swapon_all}}},
        {"enter_default_mount_ns",  {0,     0,    {false,  do_enter_default_mount_ns}}},
        {"symlink",                 {2,     2,    {true,   do_symlink}}},
        {"sysclktz",                {1,     1,    {false,  do_sysclktz}}},
        {"trigger",                 {1,     1,    {false,  do_trigger}}},
        {"verity_update_state",     {0,     0,    {false,  do_verity_update_state}}},
        {"wait",                    {1,     2,    {true,   do_wait}}},
        {"wait_for_prop",           {2,     2,    {false,  do_wait_for_prop}}},
        {"write",                   {2,     2,    {true,   do_write}}},
    };
    // clang-format on
    return builtin_functions;
}
// Builtin-function-map end

2.init.rc中的服务是如何被启动的

首先以ActionManager和ServiceList通过GetInstance分别创建单例,然后调用LoadBootScripts函数传入参数,LoadBootScripts代码如下,可以看到会先去ro.boot.init_rc中读取配置,如果为空,会进入解析init.rc的流程,否则解析配置

static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
    //创建解析器
    Parser parser = CreateParser(action_manager, service_list);

    //获取ro.boot.init_rc配置
    std::string bootscript = GetProperty("ro.boot.init_rc", "");
    if (bootscript.empty()) {
        //解析init.rc
        parser.ParseConfig("/system/etc/init/hw/init.rc");
        //如果init分区没有挂载,添加到late_import_paths
        if (!parser.ParseConfig("/system/etc/init")) {
            late_import_paths.emplace_back("/system/etc/init");
        }
        // late_import is available only in Q and earlier release. As we don't
        // have system_ext in those versions, skip late_import for system_ext.
        
        parser.ParseConfig("/system_ext/etc/init");
        //如果vender分区没有挂载,添加到late_import_paths
        if (!parser.ParseConfig("/vendor/etc/init")) {
            late_import_paths.emplace_back("/vendor/etc/init");
        }
        //如果odm分区没有挂载,添加到late_import_paths
        if (!parser.ParseConfig("/odm/etc/init")) {
            late_import_paths.emplace_back("/odm/etc/init");
        }
        //如果product分区没有挂载,添加到late_import_paths
        if (!parser.ParseConfig("/product/etc/init")) {
            late_import_paths.emplace_back("/product/etc/init");
        }
    } else {
        //解析ro.boot.init_rc
        parser.ParseConfig(bootscript);
    }
}

Android Init Language

init.rc文件是用Android Init Language编写的特殊文件,使用这种语法编写的文件,统一用.rc作为文件后缀,其语法指令规则可参考源码system/core/init/README.md文档,其中包含Commands、Options等,

Commands定义在system/core/init/builtins.cpp

Options定义在system/core/init/service_parser.cpp

后续会单独篇幅说明这个语法规则,本篇暂不展开说明。

init.rc文件在源码中的位置:system/core/rootdir/init.rc

回到SecondStageMain方法中,am.ExecuteOneCommand()函数会执行从.rc文件中解析出来的指令,跟一下这个函数,函数在./action_manager.cpp第67行:

void ActionManager::ExecuteOneCommand() {
    {
        auto lock = std::lock_guard{event_queue_lock_};
        // Loop through the event queue until we have an action to execute
        while (current_executing_actions_.empty() && !event_queue_.empty()) {
            for (const auto& action : actions_) {
                if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },
                               event_queue_.front())) {
                    current_executing_actions_.emplace(action.get());
                }
            }
            event_queue_.pop();
        }
    }

    if (current_executing_actions_.empty()) {
        return;
    }

    //从队列头获得一个action
    auto action = current_executing_actions_.front();

    if (current_command_ == 0) {
        std::string trigger_name = action->BuildTriggersString();
        LOG(INFO) << "processing action (" << trigger_name << ") from (" << action->filename()
                  << ":" << action->line() << ")";
    }

    //调用到action的ExecuteOneCommand中,current_command_代表行数
    action->ExecuteOneCommand(current_command_);

    // If this was the last command in the current action, then remove
    // the action from the executing list.
    // If this action was oneshot, then also remove it from actions_.
    ++current_command_;
    if (current_command_ == action->NumCommands()) {
        current_executing_actions_.pop();
        current_command_ = 0;
        if (action->oneshot()) {
            auto eraser = [&action](std::unique_ptr& a) { return a.get() == action; };
            actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser),
                           actions_.end());
        }
    }
}

会调用到action->ExecuteOneCommand()函数,继续跟./action.cpp:146行:

void Action::ExecuteOneCommand(std::size_t command) const {
    // We need a copy here since some Command execution may result in
    // changing commands_ vector by importing .rc files through parser
    Command cmd = commands_[command];
    //继续跟
    ExecuteCommand(cmd);
}

void Action::ExecuteCommand(const Command& command) const {
    android::base::Timer t;
    //执行了InvokeFunc
    auto result = command.InvokeFunc(subcontext_);
    auto duration = t.duration();

    // Any action longer than 50ms will be warned to user as slow operation
    if (!result.has_value() || duration > 50ms ||
        android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
        std::string trigger_name = BuildTriggersString();
        std::string cmd_str = command.BuildCommandString();

        LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << " (" << filename_
                  << ":" << command.line() << ") took " << duration.count() << "ms and "
                  << (result.ok() ? "succeeded" : "failed: " + result.error().message());
    }
}

调用到command.InvokeFunc()函数中,看看做了什么:

Result Command::InvokeFunc(Subcontext* subcontext) const {
    //从vendor 或 oem 解析出来的rc文件都会走这里,会有一定限制
    if (subcontext) {
        if (execute_in_subcontext_) {
            return subcontext->Execute(args_);
        }

        auto expanded_args = subcontext->ExpandArgs(args_);
        if (!expanded_args.ok()) {
            return expanded_args.error();
        }
        return RunBuiltinFunction(func_, *expanded_args, subcontext->context());
    }
    //原生init.rc文件命令会走这里
    return RunBuiltinFunction(func_, args_, kInitContext);
}


Result RunBuiltinFunction(const BuiltinFunction& function,
                                const std::vector& args, const std::string& context) {
    auto builtin_arguments = BuiltinArguments(context);

    builtin_arguments.args.resize(args.size());
    builtin_arguments.args[0] = args[0];
    for (std::size_t i = 1; i < args.size(); ++i) {
        auto expanded_arg = ExpandProps(args[i]);
        if (!expanded_arg.ok()) {
            return expanded_arg.error();
        }
        builtin_arguments.args[i] = std::move(*expanded_arg);
    }
    //执行这个函数
    return function(builtin_arguments);
}

function就是上面第一点提到的,当触发map中元素key调用时,会对应调用value对应的函数,这里以init.rc中一段脚本举例,看一下服务是如何启动的:

on zygote-start && ...
    ...
    start statsd
    start netd
    start zygote
    start zygote_secondary

结合上面map中的key-value对应关系,发现start对应着do_start函数,源码位置/system/core/init/builtins.cpp:

static Result do_start(const BuiltinArguments& args) {
    //通过传入的arg,查找对应服务
    Service* svc = ServiceList::GetInstance().FindService(args[1]);
    if (!svc) return Error() << "service " << args[1] << " not found";
    //通过调用start执行
    if (auto result = svc->Start(); !result.ok()) {
        return ErrorIgnoreEnoent() << "Could not start service: " << result.error();
    }
    return {};
}

通过命令搜索

grep "::Start()" ./ -rn


搜索结果
./service.cpp:397:Result Service::Start() {

函数如下


Result Service::Start() {
    ...

    pid_t pid = -1;
    //通过克隆或者fork子进程
    if (namespaces_.flags) {
        pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr);
    } else {
        pid = fork();
    }

    //子进程创建成功
    if (pid == 0) {
        //设置权限掩码
        umask(077);

        if (auto result = EnterNamespaces(namespaces_, name_, override_mount_namespace);
            !result.ok()) {
            LOG(FATAL) << "Service '" << name_
                       << "' failed to set up namespaces: " << result.error();
        }

        for (const auto& [key, value] : environment_vars_) {
            setenv(key.c_str(), value.c_str(), 1);
        }

        for (const auto& descriptor : descriptors) {
            descriptor.Publish();
        }

        if (auto result = WritePidToFiles(&writepid_files_); !result.ok()) {
            LOG(ERROR) << "failed to write pid to files: " << result.error();
        }

        if (task_profiles_.size() > 0 && !SetTaskProfiles(getpid(), task_profiles_)) {
            LOG(ERROR) << "failed to set task profiles";
        }

        // As requested, set our gid, supplemental gids, uid, context, and
        // priority. Aborts on failure.
        SetProcessAttributesAndCaps();

        //内部调用的execv来启动的程序
        if (!ExpandArgsAndExecv(args_, sigstop_)) {
            PLOG(ERROR) << "cannot execv('" << args_[0]
                        << "'). See the 'Debugging init' section of init's README.md for tips";
        }

        _exit(127);
    }

    if (pid < 0) {
        pid_ = 0;
        return ErrnoError() << "Failed to fork";
    }
    ...

    return {};
}

追一下ExpandArgsAndExecv函数:


static bool ExpandArgsAndExecv(const std::vector& args, bool sigstop) {
    std::vector expanded_args;
    std::vector c_strings;

    expanded_args.resize(args.size());
    c_strings.push_back(const_cast(args[0].data()));
    for (std::size_t i = 1; i < args.size(); ++i) {
        auto expanded_arg = ExpandProps(args[i]);
        if (!expanded_arg.ok()) {
            LOG(FATAL) << args[0] << ": cannot expand arguments': " << expanded_arg.error();
        }
        expanded_args[i] = *expanded_arg;
        c_strings.push_back(expanded_args[i].data());
    }
    c_strings.push_back(nullptr);

    if (sigstop) {
        kill(getpid(), SIGSTOP);
    }
    //有没有很熟悉,最终还是通过执行execv来执行程序文件的
    return execv(c_strings[0], c_strings.data()) == 0;
}

先通过克隆或者fork子进程,然后调用execv函数启动程序文件,由此一个服务就启动起来了。

至此一个完整的init进程启动服务就分析完成了,下一篇分析一下zygote被启动起来时做了哪些事情!

你可能感兴趣的:(android,framwork)