init.rc 语法与解析

版权说明:本文为 开开向前冲 原创文章,转载请注明出处;
注:限于作者水平有限,文中有不对的地方还请指教。

本文基于Android 6.0,涉及源码如下:

/system/core/rootdir/init.rc
/system/core/init/init_parser.cpp

一:init.rc 语法

一个完整的init.rc 脚本由4中类型声明组成。即:
Action(动作)
Commands(命令)
Services(服务)
Options(选项)

Action 和Services 表明一个新语句的开始,这两个关键字后面跟着的Commands 或者 Options 都是属于这个语句;
Action 和Services 都有唯一的名字,如果出现动作或者服务重名,则会被当做错误处理。

1:Action(动作)

语法格式

on <trigger>   ##触发条件
     <command1>  ##执行命令
     <command2>  ##可以同时执行多个命令
     <command3>

其中trigger 是触发条件,即当触发条件满足时将 依次 执行commands

举例说明:下面这句话的意思是当属性值满足persist.service.adb.enable=1时,启动adbd 进程;
on property:persist.service.adb.enable=1
   start adbd

具体实现:当系统变化的时候,系统会对init.rc 中的每个<trigger>进行匹配,只要发现符合条件的Action,就会把它加入 “命令执行队列”的尾部(除非这个Action 在队列中已经存在), 然后系统在对这些Commands按顺序执行;

2:Commands(命令)

命令将在触发条件发生时被一个个执行。

init.rc中常见的trigger如下:

triggerDescription
bootinit程序启动后触发的第一个事件
<name>=<value>当属性<name> 满足<value>时触发
device-added/removed-<patch>当设备节点添加/删除时触发此事件
sevice-exited-<name>当指定服务<name> 存在时触发

init.rc中常见的Commands如下:

CommandDescription
exec <path> [<argument>]*Fork 并执行一个程序,其路径为<path>。该命令将阻塞 直到该程序启动完成
export <name> <value>设置某个环境变量<name> 的值为<value>。对全局有效,之后的进程都将继承这个变量
ifup <interface>使网络接口<interface> 成功连接
import <filename>解析另一个配置文件<filename>,以扩展当前配置
chdir <directory>更换工作目录为<directory>
chmod <octal-mode> <path>更改文件访问权限
chown <owner> <group> <path>更改文件所有者和群组
mount <type> <device> <dir> [<mountoption>]*尝试在指定路径上挂载一个设备
start <service>启动一个服务,如果它没有处于运行状态的话
stop <service>停止一个服务,如果它当前处于运行状态的话
setprop <name> <value>设置系统属性<name> 的值为 <value>
trigger <event>触发一个事件

很多没有列举完成,但是很多Commands 可以根据名字理解意思,如下举几个例子,例子都是init.rc中的内容;

on init
      symlink /sys/kernel/debug /d
      mount cgroup none /acct cpuacct
      mkdir /acct/uid
      chown root system /sys/fs/cgroup/memory/sw/tasks
      chmod 0660 /sys/fs/cgroup/memory/sw/tasks

on property:sys.boot_from_charger_mode=1
class_stop charger
trigger late-init

3:Services(服务)

3.1:命令格式:

service <name> <pathname> [ <argument> ]*
        <option>
        <option>
        ...
  • <name>——表示service 的名字;
  • <pathname>——表示service所在路径,此处的service是可执行文件,所以一定有存储路径;
  • <argument>——启动service所带的参数;
  • <option>——对此service的约束选项,后面将详细讲解;

Service 样例如下:

service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart drm
4:Options(选项)

init.rc 中可用的选项如下:

OptionDescription
critical表明这是对设备至关重要的服务;如果它在四分钟内退出超过四次,则设备将进入Recovery 模式
disabled表示此服务是不会自动启动,而是需要通过显示调用服务名来启动
setenv <name> <value>设置环境变量<name> 为值<value>
socket <name> <type> <perm> [<user> [<group>] ]创建一个名为dev/socket/<name>的 socket,然后将它的fd值传给启动它的进,有效的<type>值包括dgram,stream 和seqpacket。ueser 和group 的默认值为0。
user <username>在启动服务前将用户切换至<username>,默认情况下用户都是root。
group <groupname> [<groupname>]*在启动服务前将用户组切换至<groupname>
oneshot当次服务退出时,不要主动去重启它
class <name>为该服务指定一个class 名。同一个class 的所有服务必须同时启动或者停止。默认情况下服务的class名是“default”
onrestart当次服务重启时,执行某些命令

二:init.rc解析

/system/core/init/init.cpp
/system/core/init/init_parser.cpp

1:init.rc脚本基本结构

init.rc 脚本的基本单位为section,即片段,section 分为三类,分别由三个关键字(所谓关键字即每一行的第一列)来区分,这三个关键字是on、service、import。

  • on ——即前文的action 的起始关键字;
    on 类型的section 表示一系列命令的组合;
 on init
    loglevel 3
    symlink /system/etc /etc
    symlink /sys/kernel/debug /d
    symlink /system/vendor /vendor
    mount cgroup none /acct cpuacct
    mkdir /acct/uid

这条命令包含上述的命令,命令的执行事以section 为单位执行的,所以这几条命令是一起执行的,而不会单独执行,那它们是在那里执行呢?——这是由init.cpp中的main()方法决定的,init.cpp在某个阶段会执行

action_for_each_trigger("init", action_add_queue_tail);

该方法就是将 on init 开始的section 里面的所有命令加入到一个执行队列,在未来的某个时间会顺序的执行,所以调用action_for_each_trigger的先后决定了命令执行的先后顺序;

  • service ——即前文所说的服务起始关键字;
    service类型的section代表了一个可执行程序;
service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart drm

服务的内容之前已经介绍过,可以看看前文,那service 类型的section标识的服务在什么时候调用呢?—— 是在class_start命令被执行的时候,class_start命令总是存在于on 类型的section中;

class_start core #这样一条命令代表将启动所有类型为core的service
所以可以看出android的启动过程主要就是on类型的section被执行的过程。

  • import —— import类型的section代表将引入另外一个.rc文件;

import /init.environ.rc
import /init.usb.rc

相当包含另外一些section, 在解析完init.rc文件后继续会调用init_parse_config_file来解析引入的.rc文件

2:解析过程

init.rc是一个纯文本文件,我们需要程序去解析init.rc,然后交给程序运行,解析init.rc的过程就是识别一个个section的过程,将各个section的信息保存下来,然后在init.c的main()中去执行一个个命令。

android采用双向链表来存储section的信息,解析完成之后,会得到三个双向链表action_list、service_list、import_list来分别存储三种section的信息上。

/system/core/init/init_parser.cpp
static list_declare(service_list);
static list_declare(action_list);
static list_declare(action_queue);

1:init.c中调用init_parse_config_file("/init.rc")

int init_parse_config_file(const char *fn)
{
    char *data;
    data = read_file(fn, 0);//读文件数据
    if (!data) return -1;
<span class="token function">parse_config</span><span class="token punctuation">(</span>fn<span class="token punctuation">,</span> <span class="token keyword">data</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//解析数据</span>
<span class="token function">DUMP</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

2:parse_config

static void parse_config(const char *fn, const std::string& data)
{
    struct listnode import_list;
    struct listnode *node;
    char *args[INIT_PARSER_MAXARGS];
<span class="token keyword">int</span> nargs <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

parse_state state<span class="token punctuation">;</span>
state<span class="token punctuation">.</span>filename <span class="token operator">=</span> fn<span class="token punctuation">;</span>
state<span class="token punctuation">.</span>line <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
state<span class="token punctuation">.</span>ptr <span class="token operator">=</span> <span class="token function">strdup</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span><span class="token function">c_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// TODO: fix this code!</span>
state<span class="token punctuation">.</span>nexttoken <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
state<span class="token punctuation">.</span>parse_line <span class="token operator">=</span> parse_line_no_op<span class="token punctuation">;</span>

<span class="token function">list_init</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>import_list<span class="token punctuation">)</span><span class="token punctuation">;</span>
state<span class="token punctuation">.</span>priv <span class="token operator">=</span> <span class="token operator">&amp;</span>import_list<span class="token punctuation">;</span>

<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token punctuation">;</span><span class="token punctuation">;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">switch</span> <span class="token punctuation">(</span><span class="token function">next_token</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>state<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//next_token()根据从state.ptr开始遍历</span>
    <span class="token keyword">case</span> T_EOF<span class="token operator">:</span> <span class="token comment">//遍历到文件结尾,然后goto解析import的.rc文件</span>
        state<span class="token punctuation">.</span><span class="token function">parse_line</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>state<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">goto</span> parser_done<span class="token punctuation">;</span>
    <span class="token keyword">case</span> T_NEWLINE<span class="token operator">:</span> <span class="token comment">//到了一行结束</span>
        state<span class="token punctuation">.</span>line<span class="token operator">++</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>nargs<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">int</span> kw <span class="token operator">=</span> <span class="token function">lookup_keyword</span><span class="token punctuation">(</span>args<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 找到这一行的关键字</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">kw_is</span><span class="token punctuation">(</span>kw<span class="token punctuation">,</span> SECTION<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 如果这是一个section的第一行</span>
                state<span class="token punctuation">.</span><span class="token function">parse_line</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>state<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token function">parse_new_section</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>state<span class="token punctuation">,</span> kw<span class="token punctuation">,</span> nargs<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token comment">//如果这不是一个section的第一行</span>
                state<span class="token punctuation">.</span><span class="token function">parse_line</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>state<span class="token punctuation">,</span> nargs<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            nargs <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">break</span><span class="token punctuation">;</span>
    <span class="token keyword">case</span> T_TEXT<span class="token operator">:</span> <span class="token comment">// 遇到普通字符</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>nargs <span class="token operator">&lt;</span> INIT_PARSER_MAXARGS<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            args<span class="token punctuation">[</span>nargs<span class="token operator">++</span><span class="token punctuation">]</span> <span class="token operator">=</span> state<span class="token punctuation">.</span>text<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">break</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

parser_done:
list_for_each(node, &import_list) {
struct import *import = node_to_item(node, struct import, list);
int ret;

     ret <span class="token operator">=</span> <span class="token function">init_parse_config_file</span><span class="token punctuation">(</span>import<span class="token operator">-&gt;</span>filename<span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token keyword">if</span> <span class="token punctuation">(</span>ret<span class="token punctuation">)</span>
         <span class="token function">ERROR</span><span class="token punctuation">(</span><span class="token string">"could not import file '%s' from '%s'\n"</span><span class="token punctuation">,</span>
               import<span class="token operator">-&gt;</span>filename<span class="token punctuation">,</span> fn<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

next_token() 解析完init.rc中一行之后,会返回T_NEWLINE,这时调用lookup_keyword函数来找出这一行的关键字, lookup_keyword返回的是一个整型值,对应keyword_info[]数组的下标,keyword_info[]存放的是keyword_info结构体类型的数据,

struct {
   const char *name;                                    //关键字的名称
   int (*func)(int nargs, char **args);            //对应的处理函数
   unsigned char nargs;                                //参数个数
   unsigned char flags;                                 //flag标识关键字的类型,包括COMMAND、OPTION、SECTION
} keyword_info

keyword_info[]中存放的是所有关键字信息,每一项对应一个关键字;
根据每一项的flags就可以判断出关键字的类型,如新的一行是SECTION,就调用parse_new_section()来解析这一行, 如新的一行不是一个SECTION的第一行,那么调用state.parseline()来解析(state.parseline所对应的函数会根据section类型的不同而不同),在parse_new_section()中进行动态设置。

static void parse_new_section(struct parse_state *state, int kw,
                       int nargs, char **args)
{
    printf("[ %s %s ]\n", args[0],
           nargs > 1 ? args[1] : "");
    switch(kw) {
    case K_service: //解析service
        state->context = parse_service(state, nargs, args);
        if (state->context) {
            state->parse_line = parse_line_service; //Service 对应的parse_line
            return;
        }
        break;
    case K_on://解析 on 开头的action
        state->context = parse_action(state, nargs, args);
        if (state->context) {
            state->parse_line = parse_line_action; //action 对应的parse_line
            return;
        }
        break;
    case K_import: //解析import
        parse_import(state, nargs, args);
        break;
    }
    state->parse_line = parse_line_no_op;
}

三种类型的section: service、on、import, service对应的state.parse_line为parse_line_service,
on对应的state.parse_line为parse_line_action, import section中只有一行所以没有对应的state.parseline。

鉴于篇幅原因,使用文字描述parse_service过程,parse_action,parse_import解析也是类似的:

parse_service会去service_list链表查找有没有该命名的service(svc = service_find_by_name(args[1]);),如果没有则会构造service 对象并添加到service_list链表中,返回该service 对象;但是这个service 没有Options,然后通过parse_line_service 解析Options选项填充service 对象;

3:相关结构体

一个on类型的section对应一个action, action类型定义如下:

struct action {
        /* node in list of all actions */
    struct listnode alist;
        /* node in the queue of pending actions */
    struct listnode qlist;
        /* node in list of actions for a trigger */
    struct listnode tlist;
<span class="token keyword">unsigned</span> hash<span class="token punctuation">;</span>

    <span class="token comment">/* list of actions which triggers the commands*/</span>
<span class="token keyword">struct</span> <span class="token class-name">listnode</span> triggers<span class="token punctuation">;</span>
<span class="token keyword">struct</span> <span class="token class-name">listnode</span> commands<span class="token punctuation">;</span> <span class="token comment">//command的双向链表</span>
<span class="token keyword">struct</span> <span class="token class-name">command</span> <span class="token operator">*</span>current<span class="token punctuation">;</span>

};

每个on类型section的第二行开始每一行都解析了一个command, 所有command组成一个双向链表指向该action的commands字段中。

command结构体定义如下:

struct command
{
        /* list of commands in an action */
    struct listnode clist;
<span class="token keyword">int</span> <span class="token punctuation">(</span><span class="token operator">*</span>func<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token keyword">int</span> nargs<span class="token punctuation">,</span> <span class="token keyword">char</span> <span class="token operator">*</span><span class="token operator">*</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">int</span> line<span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>filename<span class="token punctuation">;</span>

<span class="token keyword">int</span> nargs<span class="token punctuation">;</span>
<span class="token keyword">char</span> <span class="token operator">*</span>args<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

};

command结构体比较简单, 用于标识一个命令,包含双向链表指针、对应的执行函数、参数个数以及命令关键字。

service结构体定义如下:

struct service {
    void NotifyStateChange(const char* new_state);
    <span class="token comment">/* list of all services */</span>
<span class="token keyword">struct</span> <span class="token class-name">listnode</span> slist<span class="token punctuation">;</span>

<span class="token keyword">char</span> <span class="token operator">*</span>name<span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>classname<span class="token punctuation">;</span>

<span class="token keyword">unsigned</span> flags<span class="token punctuation">;</span>
pid_t pid<span class="token punctuation">;</span>
time_t time_started<span class="token punctuation">;</span>    <span class="token comment">/* time of last start */</span>
time_t time_crashed<span class="token punctuation">;</span>    <span class="token comment">/* first crash within inspection window */</span>
<span class="token keyword">int</span> nr_crashed<span class="token punctuation">;</span>         <span class="token comment">/* number of times crashed within window */</span>

uid_t uid<span class="token punctuation">;</span>
gid_t gid<span class="token punctuation">;</span>
gid_t supp_gids<span class="token punctuation">[</span>NR_SVC_SUPP_GIDS<span class="token punctuation">]</span><span class="token punctuation">;</span>
size_t nr_supp_gids<span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token keyword">char</span><span class="token operator">*</span> seclabel<span class="token punctuation">;</span>

<span class="token keyword">struct</span> <span class="token class-name">socketinfo</span> <span class="token operator">*</span>sockets<span class="token punctuation">;</span>
<span class="token keyword">struct</span> <span class="token class-name">svcenvinfo</span> <span class="token operator">*</span>envvars<span class="token punctuation">;</span>

<span class="token keyword">struct</span> <span class="token class-name">action</span> onrestart<span class="token punctuation">;</span>  <span class="token comment">/* Actions to execute on restart. */</span>

std<span class="token operator">::</span>vector<span class="token operator">&lt;</span>std<span class="token operator">::</span>string<span class="token operator">&gt;</span><span class="token operator">*</span> writepid_files_<span class="token punctuation">;</span>

<span class="token comment">/* keycodes for triggering this service via /dev/keychord */</span>
<span class="token keyword">int</span> <span class="token operator">*</span>keycodes<span class="token punctuation">;</span>
<span class="token keyword">int</span> nkeycodes<span class="token punctuation">;</span>
<span class="token keyword">int</span> keychord_id<span class="token punctuation">;</span>

IoSchedClass ioprio_class<span class="token punctuation">;</span>
<span class="token keyword">int</span> ioprio_pri<span class="token punctuation">;</span>

<span class="token keyword">int</span> nargs<span class="token punctuation">;</span>
<span class="token comment">/* "MUST BE AT THE END OF THE STRUCT" */</span>
<span class="token keyword">char</span> <span class="token operator">*</span>args<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

};

service结构体存储了service的相关信息, 包括进程号、启动时间、名字等, onrestart这个option后面通常跟着一个命令,所以也用action结构体来表示。
例如:

service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart drm
init.rc中配置的service 启动流程:
/system/core/rootdir/init.rc
      class_start core
  on nonencrypted
      class_start main
      class_start late_start

/system/core/init/keywords.h
KEYWORD(class_start, COMMAND, 1, do_class_start)

/system/core/init/builtins.c
int do_class_start(int nargs, char args)
{
/* Starting a class does not start services
* which are explicitly disabled. They must
* be started individually.
*/

service_for_each_class(args[1], service_start_if_not_disabled);
return 0;
}

/system/core/init/init_parser.cpp
void service_for_each_class(const char classname,
void (func)(struct service svc))
{
struct listnode node;
struct service *svc;
list_for_each(node, &service_list) {
svc = node_to_item(node, struct service, slist);
if (!strcmp(svc->classname, classname)) {
func(svc);
}
}
}

/system/core/init/builtins.cpp
static void service_start_if_not_disabled(struct service *svc)
{
if (!(svc->flags & SVC_DISABLED)) {
service_start(svc, NULL);
} else {
svc->flags |= SVC_DISABLED_START;
}
}

/system/core/init/init.c
void service_start(struct service svc, const char dynamic_args)
{
struct stat s;
pid_t pid;
int needs_console;
int n;
char *scon = NULL;
int rc;

    <span class="token comment">/* starting a service removes it from the disabled or reset
     * state and immediately takes it out of the restarting
     * state if it was in there
     */</span>
  <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
  pid <span class="token operator">=</span> <span class="token function">fork</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//fork 子进程</span>
  <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
  <span class="token keyword">for</span> <span class="token punctuation">(</span>si <span class="token operator">=</span> svc<span class="token operator">-&gt;</span>sockets<span class="token punctuation">;</span> si<span class="token punctuation">;</span> si <span class="token operator">=</span> si<span class="token operator">-&gt;</span>next<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">int</span> socket_type <span class="token operator">=</span> <span class="token punctuation">(</span>
                <span class="token operator">!</span><span class="token function">strcmp</span><span class="token punctuation">(</span>si<span class="token operator">-&gt;</span>type<span class="token punctuation">,</span> <span class="token string">"stream"</span><span class="token punctuation">)</span> <span class="token punctuation">?</span> SOCK_STREAM <span class="token punctuation">:</span>
                    <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">strcmp</span><span class="token punctuation">(</span>si<span class="token operator">-&gt;</span>type<span class="token punctuation">,</span> <span class="token string">"dgram"</span><span class="token punctuation">)</span> <span class="token punctuation">?</span> SOCK_DGRAM <span class="token punctuation">:</span> SOCK_SEQPACKET<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//判断socket 类型</span>
        <span class="token keyword">int</span> s <span class="token operator">=</span> <span class="token function">create_socket</span><span class="token punctuation">(</span>si<span class="token operator">-&gt;</span>name<span class="token punctuation">,</span> socket_type<span class="token punctuation">,</span>
                              si<span class="token operator">-&gt;</span>perm<span class="token punctuation">,</span> si<span class="token operator">-&gt;</span>uid<span class="token punctuation">,</span> si<span class="token operator">-&gt;</span>gid<span class="token punctuation">,</span> si<span class="token operator">-&gt;</span>socketcon <span class="token punctuation">?</span><span class="token punctuation">:</span> scon<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//创建socket对应的fd</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>s <span class="token operator">&gt;=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token function">publish_socket</span><span class="token punctuation">(</span>si<span class="token operator">-&gt;</span>name<span class="token punctuation">,</span> s<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//发布socket的fd,即将create_socket返回的fd添加到</span>
                                        <span class="token comment">//以"ANDROID_SOCKET_"为前缀的环境变量;</span>
                                        <span class="token comment">//Zygote的socket的key 为ANDROID_SOCKET_zygote,也是在这创建的;</span>
        <span class="token punctuation">}</span>
   <span class="token punctuation">}</span>
  <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值