Android7.0解析Init.rc文件

    在解析Init.rc之前需要对init.rc文件有一个认识,init.rc是由一种被称为"Android初始化语言"(Android Init Language,这里简称为AIL)的脚本写成的文件.该语言是由语句组成的,主要包含了五种类型的语句:

  1. Action
  2. Commands
  3. Services
  4. Options
  5. Import

 在init.rc文件中一条语句通常占用一行,单词之间是用空格符来相隔的。如果一行写不下,可以在行尾加上反斜杠,来连接下一行。也就是说,可以用反斜杠将多行代码连接成一行代码。并且使用#来进行注释。在init.rc中分成三个部分(Section),而每一部分的开头需要指定on(Actions)、service(Services)或import。也就是说,每一个Actions, import或 Services确定一个Section。而所有的Commands和Options只能属于最近定义的Section。如果Commands和 Options在第一个Section之前被定义,它们将被忽略。Actions和Services的名称必须唯一。如果有两个或多个Actions或Services拥有同样的名称,那么init在执行它们时将抛出错误,并忽略这些Action和Service。

我们在之前分析init进程时讲到过在init.cpp的main函数中将service, on, import设置为三个Section.

    Parser& parser = Parser::GetInstance();
    parser.AddSectionParser("service",std::make_unique());
    parser.AddSectionParser("on", std::make_unique());
    parser.AddSectionParser("import", std::make_unique());
下面来看一下Action,Service,Import都是该怎么定义的.

在system/core/init/readme.txt中详细说明

Action的格式如下:

on  [&& ]*     //设置触发器
   
                     //动作触发之后要执行的命令
   
Triggers                    //对trigger的详细讲解
--------
Triggers are strings which can be used to match certain kinds of
events and used to cause an action to occur.

Triggers are subdivided into event triggers and property triggers.

Event triggers are strings triggered by the 'trigger' command or by
the QueueEventTrigger() function within the init executable.  These
take the form of a simple string such as 'boot' or 'late-init'.

Property triggers are strings triggered when a named property changes
value to a given new value or when a named property changes value to
any new value.  These take the form of 'property:=' and
'property:=*' respectively.  Property triggers are additionally
evaluated and triggered accordingly during the initial boot phase of
init.

An Action can have multiple property triggers but may only have one
event trigger.

For example:
'on boot && property:a=b' defines an action that is only executed when
the 'boot' event trigger happens and the property a equals b.

'on property:a=b && property:c=d' defines an action that is executed
at three times,
   1) During initial boot if property a=b and property c=d
   2) Any time that property a transitions to value b, while property
      c already equals d.
   3) Any time that property c transitions to value d, while property
      a already equals b.

在init.cpp中设置的trigger有early-init, init, late-init等, 当trigger被触发时就执行command,

我们来看一个标准的Action:

on early-init     //trigger为early-init,在init.cpp的main函数中设置过
    # Set init and its forked children's oom_adj.
    write /proc/1/oom_score_adj -1000   //调用do_write函数, 写入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       //为adb_keys 重置安全上下文

    # Shouldn't be necessary, but sdcard won't start without it. http://b/22568628.
    mkdir /mnt 0775 root system    //创建mnt目录

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

    start ueventd       //调用函数do_start, 启动服务uevent,

下面对所有命令详细讲解.

bootchart_init    //初始化bootchart,用于获取开机过程系统信息
   Start bootcharting if configured (see below).
   This is included in the default init.rc.

chmod    //改变文件的权限
   Change file access permissions.

chown     //改变文件的群组
   Change file owner and group.

class_start    //启动所有具有特定class的services
   Start all services of the specified class if they are
   not already running.

class_stop       //将具有特定class的所有运行中的services给停止或者diasble
   Stop and disable all services of the specified class if they are
   currently running.

class_reset    //先将services stop掉, 之后可能会通过class_start再重新启动起来
   Stop all services of the specified class if they are
   currently running, without disabling them. They can be restarted
   later using class_start.

copy      //复制文件
   Copies a file. Similar to write, but useful for binary/large
   amounts of data.

domainname     
   Set the domain name.

enable   //如果services没有特定disable,就将他设为enable
   Turns a disabled service into an enabled one as if the service did not
   specify disabled.        
   If the service is supposed to be running, it will be started now.
   Typically used when the bootloader sets a variable that indicates a specific
   service should be started when needed. E.g.
     on property:ro.boot.myfancyhardware=1
        enable my_fancy_service_for_my_fancy_hardware

exec [  [  [  ]* ] ] --  [  ]*    //创建执行程序.比较重要,后面启动service要用到
   Fork and execute command with the given arguments. The command starts
   after "--" so that an optional security context, user, and supplementary
   groups can be provided. No other commands will be run until this one
export        //在全局设置环境变量
   Set the environment variable  equal to  in the
   global environment (which will be inherited by all processes
   started after this command is executed)

hostname        //设置主机名称
   Set the host name.

ifup        //启动网络接口
   Bring the network interface  online.

insmod     //在某个路径安装一个模块
   Install the module at 

load_all_props    //加载所有的配置
   Loads properties from /system, /vendor, et cetera.
   This is included in the default init.rc.

load_persist_props  //当data加密时加载一些配置
   Loads persistent properties when /data has been decrypted.
   This is included in the default init.rc.

loglevel        //设置kernel log level
   Sets the kernel log level to level. Properties are expanded within .

mkdir  [mode] [owner] [group]    //创建文件夹
   Create a directory at , optionally with the given mode, owner, and
   group. If not provided, the directory is created with permissions 755 and
   owned by the root user and root group. If provided, the mode, owner and group
   will be updated if the directory exists already.

mount_all  [  ]*      //挂载
   Calls fs_mgr_mount_all on the given fs_mgr-format fstab and imports .rc files
   at the specified paths (e.g., on the partitions just mounted). Refer to the
   section of "Init .rc Files" for detail.

mount    [  ]* []   //在dir文件夹下面挂载设备
   Attempt to mount the named device at the directory 
    may be of the form mtd@name to specify a mtd block
   device by name.
   s include "ro", "rw", "remount", "noatime", ...
    include "barrier=1", "noauto_da_alloc", "discard", ... as
   a comma separated string, eg: barrier=1,noauto_da_alloc

powerctl
   Internal implementation detail used to respond to changes to the
   "sys.powerctl" system property, used to implement rebooting.
restart           //重启服务
   Like stop, but doesn't disable the service.

restorecon  [  ]*      //重置文件的安全上下文
   Restore the file named by  to the security context specified
   in the file_contexts configuration.
   Not required for directories created by the init.rc as these are
   automatically labeled correctly by init.

restorecon_recursive  [  ]*//一般都是 selinux完成初始化之后又创建、或者改变的目录
   Recursively restore the directory tree named by  to the
   security contexts specified in the file_contexts configuration.

rm          //删除文件
   Calls unlink(2) on the given path. You might want to
   use "exec -- rm ..." instead (provided the system partition is
   already mounted).

rmdir      //删除文件夹
   Calls rmdir(2) on the given path.

setprop      //设置属性
   Set system property  to . Properties are expanded
   within .

setrlimit   
   Set the rlimit for a resource.

start      //如果service没有启动,就将他启动起来
   Start a service running if it is not already running.

stop  //将运行的服务停掉
   Stop a service from running if it is currently running.

swapon_all 
   Calls fs_mgr_swapon_all on the given fstab file.

symlink  
   Create a symbolic link at  with the value 

sysclktz 
   Set the system clock base (0 if system clock ticks in GMT)
trigger       //触发一个事件
   Trigger an event.  Used to queue an action from another
   action.

verity_load_state
   Internal implementation detail used to load dm-verity state.

verity_update_state 
   Internal implementation detail used to update dm-verity state and
   set the partition..verified properties used by adb remount
   because fs_mgr can't set them directly itself.

wait  [  ]     //等待
   Poll for the existence of the given file and return when found,
   or the timeout has been reached. If timeout is not specified it
   currently defaults to five seconds.

write     //写文件
   Open the file at  and write a string to it with write(2).
   If the file does not exist, it will be created. If it does exist,
   it will be truncated. Properties are expanded within .

这些命令在执行时会通过在BuiltinFunctionMap中的对应关系找到自己对应的函数.

Services格式如下:

service   [  ]*   //service的名字,启动路径,以及参数
   
Options        //所有的options命令如下
-------
Options are modifiers to services.  They affect how and when init
runs the service.

critical     //表示该service非常重要,如果退出四次以上在4分钟内,设备就会重启进入recovery模式
  This is a device-critical service. If it exits more than four times in
  four minutes, the device will reboot into recovery mode.

disabled    //该services不能通过class启动,只能通过name将他启动
  This service will not automatically start with its class.
  It must be explicitly started by name.

setenv     //设置环境变量
  Set the environment variable  to  in the launched process.

socket    [  [  [  ] ] ]
  Create a unix domain socket named /dev/socket/ and pass
  its fd to the launched process.   must be "dgram", "stream" or "seqpacket".
  User and group default to 0.
  'seclabel' is the SELinux security context for the socket.
  It defaults to the service security context, as specified by seclabel or
  computed based on the service executable file security context.

user 
  Change to username before exec'ing this service.
  Currently defaults to root.  (??? probably should default to nobody)
  As of Android M, processes should use this option even if they
  require linux capabilities.  Previously, to acquire linux
  capabilities, a process would need to run as root, request the
  capabilities, then drop to its desired uid.  There is a new
  mechanism through fs_config that allows device manufacturers to add
  linux capabilities to specific binaries on a file system that should
  be used instead. This mechanism is described on
  http://source.android.com/devices/tech/config/filesystem.html.  When
  using this new mechanism, processes can use the user option to
  select their desired uid without ever running as root.

group  [  ]*
  Change to groupname before exec'ing this service.  Additional
  groupnames beyond the (required) first one are used to set the
  supplemental groups of the process (via setgroups()).
  Currently defaults to root.  (??? probably should default to nobody)

seclabel 
  Change to 'seclabel' before exec'ing this service.
  Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
  Services on the system partition can instead use policy-defined transitions
  based on their file security context.
  If not specified and no transition is defined in policy, defaults to the init context.

oneshot 
  Do not restart the service when it exits.

class    //一个特定的name, 所有有这个name的service统一管理,一起启动,一起stop
  Specify a class name for the service.  All services in a
  named class may be started or stopped together.  A service
  is in the class "default" if one is not specified via the
  class option.

onrestart      //当服务重启时执行
  Execute a Command (see below) when service restarts.

writepid 
  Write the child's pid to the given files when it forks. Meant for
  cgroup/cpuset usage.
下面看一下zygote服务示例代码位置system/core/rootdir/init.zygote64.rc;

service的名字为zygote, 启动路径为手机中/system/bin/app_process64后面的都是启动参数.

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server 
    class main      //zygote的name为main,和class name为main的一块被启动
    socket zygote stream 660 root system   //为zygote创建socket
    onrestart write /sys/android_power/request_state wake  //当zygote重启时执行下面动作
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
对Action与Services了解之后就可以开始解析init.rc文件了.

在分析init进程时知道解析init.rc文件的入口在init.cpp的main函数中

    parser.ParseConfig("/init.rc");
解析init.rc的核心在system/core/init/init_parse.cpp文件中

bool Parser::ParseConfig(const std::string& path) {
    if (is_dir(path.c_str())) {       //如果路径为文件夹,就调用解析文件夹的函数
        return ParseConfigDir(path);   
    }
    return ParseConfigFile(path);  //解析init.rc文件
}

bool Parser::ParseConfigFile(const std::string& path) {
    INFO("Parsing file %s...\n", path.c_str());  //根据之前讲解klog一文,可知该log打印不出
    Timer t;      //利用Timer计时,解析文件耗时多长时间
    std::string data;
    if (!read_file(path.c_str(), &data)) {   //读取文件
        return false;
    }

    data.push_back('\n'); // TODO: fix parse_config.
    ParseData(path, data);     //解析内容
    for (const auto& sp : section_parsers_) {
        sp.second->EndFile(path);       //解析完init.rc文件后, 调用Import_parse.cpp的EndFile函数,解析引用的rc文件
    }

    // Turning this on and letting the INFO logging be discarded adds 0.2s to
    // Nexus 9 boot time, so it's disabled by default.
    if (false) DumpState();

    NOTICE("(Parsing %s took %.2fs.)\n", path.c_str(), t.duration());  //打印出解析哪个文件,花费多长时间, 来查找耗时点
    return true;
}
void Parser::ParseData(const std::string& filename, const std::string& data) {
    //TODO: Use a parser with const input and remove this copy
    std::vector data_copy(data.begin(), data.end());     //数据copy
    data_copy.push_back('\0');

    parse_state state;
    state.filename = filename.c_str();
    state.line = 0;
    state.ptr = &data_copy[0];
    state.nexttoken = 0;

    SectionParser* section_parser = nullptr;
    std::vector args;

    for (;;) {        //循环解析init.rc文件
        switch (next_token(&state)) {  //通过nextToken函数获得需要解析的这一行是文本内容还是action,services
        case T_EOF:             //文件解析结束
            if (section_parser) {
                section_parser->EndSection();   
            }
            return;
        case T_NEWLINE:      //解析新的一行, 可能是一个action,services或者import
            state.line++;
            if (args.empty()) {
                break;
            }
            if (section_parsers_.count(args[0])) {
                if (section_parser) {
                    section_parser->EndSection();   //section解析结束
                }
                section_parser = section_parsers_[args[0]].get();
                std::string ret_err;
                if (!section_parser->ParseSection(args, &ret_err)) {  //解析Action,Service, Import 三个Section
                    parse_error(&state, "%s\n", ret_err.c_str());
                    section_parser = nullptr;
                }
            } else if (section_parser) {
                std::string ret_err;      //解析section的内容
                if (!section_parser->ParseLineSection(args, state.filename,
                                                      state.line, &ret_err)) {
                    parse_error(&state, "%s\n", ret_err.c_str());
                }
            }
            args.clear();
            break;
        case T_TEXT:
            args.emplace_back(state.text);     //将文本放入args中
            break;
        }
    }
}

nextToken函数在/system/core/init/parse.cpp中实现

int next_token(struct parse_state *state)
{
    char *x = state->ptr;
    char *s;

    if (state->nexttoken) {
        int t = state->nexttoken;
        state->nexttoken = 0;
        return t;
    }

    for (;;) { 
        switch (*x) {
        case 0:
            state->ptr = x;
            return T_EOF;
        case '\n':
            x++;
            state->ptr = x;
            return T_NEWLINE;
        case ' ':
        case '\t':
        case '\r':
            x++;
            continue;
        case '#': 
            while (*x && (*x != '\n')) x++;
            if (*x == '\n') {
                state->ptr = x+1;
                return T_NEWLINE;
            } else {
                state->ptr = x;
                return T_EOF;
            }
        default: 
            goto text;
        }
    }

textdone:
    state->ptr = x;
    *s = 0;
    return T_TEXT;
text:
    state->text = s = x;
textresume:
    for (;;) {
        switch (*x) {
        case 0:
            goto textdone;
        case ' ':
        case '\t':
        case '\r':
            x++;
            goto textdone;
        case '\n':
            state->nexttoken = T_NEWLINE;
            x++;
            goto textdone;
        case '"':
            x++;
            for (;;) {
                switch (*x) {
                case 0:
                        /* unterminated quoted thing */
                    state->ptr = x;
                    return T_EOF;
                case '"':
                    x++;
                    goto textresume;
                default:
                    *s++ = *x++;
                }
            }
            break;
        case '\\':
            x++;
            switch (*x) {
            case 0:
                goto textdone;
            case 'n':
                *s++ = '\n';
                break;
            case 'r':
                *s++ = '\r';
                break;
            case 't':
                *s++ = '\t';
                break;
            case '\\':
                *s++ = '\\';
                break;
            case '\r':
                    /* \   -> line continuation */
                if (x[1] != '\n') {
                    x++;
                    continue;
                }
            case '\n':
                    /* \  -> line continuation */
                state->line++;
                x++;
                    /* eat any extra whitespace */
                while((*x == ' ') || (*x == '\t')) x++;
                continue;
            default:
                    /* unknown escape -- just copy */
                *s++ = *x++;
            }
            continue;
        default:
            *s++ = *x++;
        }
    }
    return T_EOF;

解析Action

调用ActionParser的ParseSection函数,代码位置system/core/init/action.cpp

bool ActionParser::ParseSection(const std::vector& args,
                                std::string* err) {
    std::vector triggers(args.begin() + 1, args.end());  //获取trigger, 截取on后面的字符串
    if (triggers.size() < 1) {
        *err = "actions must have a trigger";    //检查是否存在trigger
        return false;
    }

    auto action = std::make_unique(false);
    if (!action->InitTriggers(triggers, err)) {   //将triggers放入event_trigger_
        return false;
    }

    action_ = std::move(action);   //赋值action_
    return true;
}
bool ActionParser::ParseLineSection(const std::vector& args,
                                    const std::string& filename, int line,
                                    std::string* err) const {
    return action_ ? action_->AddCommand(args, filename, line, err) : false;  //action_为true ,已经赋过值
}
bool Action::AddCommand(const std::vector& args,
                        const std::string& filename, int line, std::string* err) {
    if (!function_map_) {        //function_map在分析init进程时有提到, 为true
        *err = "no function map available";
        return false;
    }

    if (args.empty()) {
        *err = "command needed, but not provided";
        return false;
    }

    auto function = function_map_->FindFunction(args[0], args.size() - 1, err);   //根据命令找到对应的函数
    if (!function) {
        return false;
    }

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

void Action::AddCommand(BuiltinFunction f,
                        const std::vector& args,
                        const std::string& filename, int line) {
    commands_.emplace_back(f, args, filename, line);  //将对应函数, 参数,文件名放入commans_中
}
void ActionParser::EndSection() {
    if (action_ && action_->NumCommands() > 0) {
        ActionManager::GetInstance().AddAction(std::move(action_));  //将一个action的所有command都加入action_后,将action_加入action列表
    }
}
void ActionManager::AddAction(std::unique_ptr action) {
    auto old_action_it =
        std::find_if(actions_.begin(), actions_.end(),
                     [&action] (std::unique_ptr& a) {
                         return action->TriggersEqual(*a);
                     });

    if (old_action_it != actions_.end()) {
        (*old_action_it)->CombineAction(*action);
    } else {
        actions_.emplace_back(std::move(action));   //将所有的action加入actions_列表
    }
}
解析Services
调用ServiceParser的ParseSection函数,代码位置system/core/init/service.cpp
bool ServiceParser::ParseSection(const std::vector& args,
                                 std::string* err) {
    if (args.size() < 3) {    //判断service是否有name与可执行程序
        *err = "services must have a name and a program";
        return false;
    }

    const std::string& name = args[1];
    if (!IsValidName(name)) {    //检查name是否可用
        *err = StringPrintf("invalid service name '%s'", name.c_str());
        return false;
    }

    std::vector str_args(args.begin() + 2, args.end()); //获取执行程序与参数
    service_ = std::make_unique(name, "default", str_args);   //给service_赋值
    return true;
}
bool ServiceParser::ParseLineSection(const std::vector& args,
                                     const std::string& filename, int line,
                                     std::string* err) const {
    return service_ ? service_->HandleLine(args, err) : false;  //service_为true, 调用HandleLine
}
Service::OptionHandlerMap::Map& Service::OptionHandlerMap::map() const {
    constexpr std::size_t kMax = std::numeric_limits::max();
    static const Map option_handlers = {   //option对应的函数
        {"class",       {1,     1,    &Service::HandleClass}},
        {"console",     {0,     0,    &Service::HandleConsole}},
        {"critical",    {0,     0,    &Service::HandleCritical}},
        {"disabled",    {0,     0,    &Service::HandleDisabled}},
        {"group",       {1,     NR_SVC_SUPP_GIDS + 1, &Service::HandleGroup}},
        {"ioprio",      {2,     2,    &Service::HandleIoprio}},
        {"keycodes",    {1,     kMax, &Service::HandleKeycodes}},
        {"oneshot",     {0,     0,    &Service::HandleOneshot}},
        {"onrestart",   {1,     kMax, &Service::HandleOnrestart}},
        {"seclabel",    {1,     1,    &Service::HandleSeclabel}},
        {"setenv",      {2,     2,    &Service::HandleSetenv}},
        {"socket",      {3,     6,    &Service::HandleSocket}},
        {"user",        {1,     1,    &Service::HandleUser}},
        {"writepid",    {1,     kMax, &Service::HandleWritepid}},
    };
    return option_handlers;
}

bool Service::HandleLine(const std::vector& args, std::string* err) {
    if (args.empty()) {
        *err = "option needed, but not provided";
        return false;
    }

    static const OptionHandlerMap handler_map;   //获得option对应的函数表
    auto handler = handler_map.FindFunction(args[0], args.size() - 1, err); //根据option获取对应的函数名

    if (!handler) {
        return false;
    }

    return (this->*handler)(args, err);   
}
void ServiceParser::EndSection() {
    if (service_) {
        ServiceManager::GetInstance().AddService(std::move(service_));
    }
}
void ServiceManager::AddService(std::unique_ptr service) {
    Service* old_service = FindServiceByName(service->name());
    if (old_service) {    //service已经被定义过了就抛弃
        ERROR("ignored duplicate definition of service '%s'",
              service->name().c_str());
        return;
    }
    services_.emplace_back(std::move(service));  //将service添加services_列表
}
解析Import
调用ImportParser的ParseSection函数,代码位置system/core/init/import_parser.cpp
bool ImportParser::ParseSection(const std::vector& args,
                                std::string* err) {
    if (args.size() != 2) {
        *err = "single argument needed for import\n";
        return false;
    }

    std::string conf_file;
    bool ret = expand_props(args[1], &conf_file); //获取引用的conf_file文件, 
    if (!ret) {
        *err = "error while expanding import";
        return false;
    }

    INFO("Added '%s' to import list\n", conf_file.c_str());
    imports_.emplace_back(std::move(conf_file));   //将所有的conf_file添加到imports_列表
    return true;
}
前面讲过当调用完ParseData函数后,会遍历所有section执行endFile函数

void ImportParser::EndFile(const std::string& filename) {
    auto current_imports = std::move(imports_);  //获取imports_
    imports_.clear();   //将imports_列表清空
    for (const auto& s : current_imports) {  //遍历列表
        if (!Parser::GetInstance().ParseConfig(s)) {   //调用ParseConfig函数,对其他配置进行解析, 流程遇上面的相同
            ERROR("could not import file '%s' from '%s': %s\n",
                  s.c_str(), filename.c_str(), strerror(errno));
        }
    }
}

到此init.rc文件就解析完了, 那么大家就想知道了解析完的actions与services又是如何执行的呢? 

请阅读启动zygote流程解析。


你可能感兴趣的:(Android启动流程)