Android init与zygote启动

Posted cao_null

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android init与zygote启动相关的知识,希望对你有一定的参考价值。

init是android用户空间启动的第一个进程。

代码基于Android 8

涉及类路径

/system/core/init/init.cpp

/system/core/rootdir/init.rc

/system/core/init/init_parser.cpp

/system/core/init/action.cpp

/system/core/init/keyword_map.h

/system/core/init/service.cpp 

/system/core/rootdir/init.zygote64_32.rc

/system/core/rootdir/目录下有多个文件

 这里能看到init.rc还有zygote32和64位的单独版本,分别对应32位和64位系统。还有init.zygote32_64.rc,代表会启动两个进程,主进程是32。

init.rc

接下来具体看看init.rc都做了什么

可以通过readme先熟悉语法

//README.md

//暂时只关注最关键的部分

The intention of these directories is:
    //核心
   1. /system/etc/init/ is for core system items such as
      SurfaceFlinger, MediaService, and logcatd.
    //SoC
   2. /vendor/etc/init/ is for SoC vendor items such as actions or
      daemons needed for core SoC functionality.
    //odm制造商
   3. /odm/etc/init/ is for device manufacturer items such as
      actions or daemons needed for motion sensor or other peripheral
      functionality.

//然后是具体的语法
//一组trigger触发的命令
Actions
    on <trigger> [&& <trigger>]*
       <command>
       <command>
       <command>

//init启动的服务,能重启
Services
    service <name> <pathname> [ <argument> ]*
       <option>
       <option>

//services参数
Options
    `console [<console>]`

//判断条件触发器
Triggers
    `on property:a=b && property:c=d` defines an action that is executed

//具体命令
Commands
    `bootchart [start|stop]`

//api不贴了用到再查
//init.rc

import /init.environ.rc
import /init.usb.rc
import /init.$ro.hardware.rc
import /vendor/etc/init/hw/init.$ro.hardware.rc
import /init.usb.configfs.rc
import /init.$ro.zygote.rc

on early-init
    # Set init and its forked children's oom_adj.
    write /proc/1/oom_score_adj -1000

    # Disable sysrq from keyboard
    write /proc/sys/kernel/sysrq 0

    # Set the security context of /adb_keys if present.
    restorecon /adb_keys

    ... //各种初始化

on init
    //boot时候的操作,大量文件句柄创建
...

# Mount filesystems and start core system services.
on late-init
    ...
    //启动zygote
    # Now we can start zygote for devices with file based encryption
    trigger zygote-start

    # Load persist properties and override properties (if enabled) from /data.
    trigger load_persist_props_action

    # Remove a file to wake up anything waiting for firmware.
    trigger firmware_mounts_complete

    trigger early-boot
    trigger boot

...

# It is recommended to put unnecessary data/ initialization from post-fs-data
# to start-zygote in device's init.rc to unblock zygote start.
//不同参数启动zygote
on zygote-start && property:ro.crypto.state=unencrypted
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

on zygote-start && property:ro.crypto.state=unsupported
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

on boot
    # basic network init
    ifup lo
    hostname localhost
    domainname localdomain

    # Memory management.  Basic kernel parameters, and allow the high
    # level system server to be able to adjust the kernel OOM driver
    # parameters to match how it is managing things.
    write /proc/sys/vm/overcommit_memory 1
    write /proc/sys/vm/min_free_order_shift 4
    chown root system /sys/module/lowmemorykiller/parameters/adj
    chmod 0664 /sys/module/lowmemorykiller/parameters/adj
    chown root system /sys/module/lowmemorykiller/parameters/minfree
    chmod 0664 /sys/module/lowmemorykiller/parameters/minfree

    ...//各种权限等操作

    //启动hal
    # Start standard binderized HAL daemons
    class_start hal

    class_start core


...
//启动各种service
service console /system/bin/sh
    class core
    console
    disabled
    user shell
    group shell log readproc
    seclabel u:r:shell:s0

on property:ro.debuggable=1
    # Give writes to anyone for the trace folder on debug builds.
    # The folder is used to store method traces.
    chmod 0773 /data/misc/trace
    start console

service flash_recovery /system/bin/install-recovery.sh
    class main
    oneshot

 init入口

Parser负责上面配置文件的解析

//init.cpp


#include <android-base/file.h>
#include <android-base/properties.h>
#include "init_parser.h"

using android::base::GetProperty;
using android::base::StringPrintf;

int main(int argc, char** argv) 
    
    ...
    const BuiltinFunctionMap function_map;
    Action::set_function_map(&function_map);

    Parser& parser = Parser::GetInstance();
    parser.AddSectionParser("service",std::make_unique<ServiceParser>());
    parser.AddSectionParser("on", std::make_unique<ActionParser>());
    parser.AddSectionParser("import", std::make_unique<ImportParser>());
    std::string bootscript = GetProperty("ro.boot.init_rc", "");
    //判断ro.boot.init_rc属性是否是空
    if (bootscript.empty()) 
        //依次取init.rc
        parser.ParseConfig("/init.rc");
        parser.set_is_system_etc_init_loaded(
            parser.ParseConfig("/system/etc/init"));
        parser.set_is_vendor_etc_init_loaded(
            parser.ParseConfig("/vendor/etc/init"));
        parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
     else 
        //厂商自己定制的
        parser.ParseConfig(bootscript);
        parser.set_is_system_etc_init_loaded(true);
        parser.set_is_vendor_etc_init_loaded(true);
        parser.set_is_odm_etc_init_loaded(true);
    
    ...
    if (bootmode == "charger") 
        am.QueueEventTrigger("charger");
     else 
        am.QueueEventTrigger("late-init");//init最后会执行late-init
    

Parser对应着init_parser.cpp

//init_parser.cpp

void Parser::AddSectionParser(const std::string& name,
                              std::unique_ptr<SectionParser> parser) 
    section_parsers_[name] = std::move(parser);

配置语句,on early-init 用到的SectionParser实际上对应着init.cpp传入的子类ActionParser 。先看/system/core/init/action.cpp里面的ParseSection方法。

//action.cpp

bool Action::ParsePropertyTrigger(const std::string& trigger, std::string* err) 
    const static std::string prop_str("property:");
    std::string prop_name(trigger.substr(prop_str.length()));
    //=分割成键值对
    size_t equal_pos = prop_name.find('=');
    if (equal_pos == std::string::npos) 
        *err = "property trigger found without matching '='";
        return false;
    

    std::string prop_value(prop_name.substr(equal_pos + 1));
    prop_name.erase(equal_pos);

    if (auto [it, inserted] = property_triggers_.emplace(prop_name, prop_value); !inserted) 
        *err = "multiple property triggers found for same property";
        return false;
    
    return true;

 重点看ParseLineSection

//system/core/init/action.cpp

bool ActionParser::ParseLineSection(const std::vector<std::string>& args,
                                    const std::string& filename, int line,
                                    std::string* err) const 
    //调用AddCommand
    return action_ ? action_->AddCommand(args, filename, line, err) : false;



bool Action::AddCommand(const std::vector<std::string>& args,
                        const std::string& filename, int line, std::string* err) 
    if (!function_map_) 
        *err = "no function map available";
        return false;
    

    if (args.empty()) 
        *err = "command needed, but not provided";
        return false;
    
    //传入FindFunction
    auto function = function_map_->FindFunction(args[0], args.size() - 1, err);
    if (!function) 
        return false;
    

    AddCommand(function, args, filename, line);
    return true;

FindFunction定义在/system/core/init/keyword_map.h,最终map()由/system/core/init/builtins.cpp来定义

//system/core/init/builtins.cpp

BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const 
    constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
    // clang-format off
    static const Map builtin_functions = 
        "bootchart",               1,     1,    do_bootchart,
        "chmod",                   2,     2,    do_chmod,
        "chown",                   2,     3,    do_chown,
        ...
        "start",                   1,     1,    do_start,
        ...
    ;
    // clang-format on
    return builtin_functions;

回头来看start zygote,对应执行do_start方法

//system/core/init/builtins.cpp


static int do_start(const std::vector<std::string>& args) 
    //通过名称搜索对应Service
    Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
    if (!svc) 
        LOG(ERROR) << "do_start: Service " << args[1] << " not found";
        return -1;
    
    //执行Start方法
    if (!svc->Start())
        return -1;
    return 0;

跳转到Service.cpp

//system/core/init/service.cpp

bool Service::Start() 
    ...
    //各种检查忽略

    LOG(INFO) << "starting service '" << name_ << "'...";

    pid_t pid = -1;
    if (namespace_flags_) 
        //有namespace_flags_则clone子进程
        pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
     else 
        //否则fork子进程
        pid = fork();
    

    if (pid == 0) 

        std::vector<char*> strs;
        ExpandArgs(args_, &strs);//先展开参数
        //然后执行
        if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) 
            PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
        

        _exit(127);
    

    if (pid < 0) 
        //创建紫禁城失败
        PLOG(ERROR) << "failed to fork for '" << name_ << "'";
        pid_ = 0;
        return false;
    

    ...

Start开启一个新的子进程,然后执行子进程的二进制,最后传入配置的参数,我们来看配置文件,先选init.zygote64_32.rc作为例子。

//system/core/rootdir/init.zygote64_32.rc

//启动zygote,路径在/system/bin/app_process64  后面都是配置参数
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    priority -20
    user root
    group root readproc
    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_secondary
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
    class main
    priority -20
    user root
    group root readproc
    socket zygote_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks

未完待续

以上是关于Android init与zygote启动的主要内容,如果未能解决你的问题,请参考以下文章

Android init与zygote启动

Android启动过程——init,Zygote,SystemServer

Android Framework实战视频--系统init到init.rc的Zygote的启动

Android Zygote进程启动分析

Android 进阶——系统启动之核心SystemServer进程启动详解

Android 进阶——系统启动之核心SystemServer进程启动详解