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如下:

trigger Description
boot init程序啓動後觸發的第一個事件
<name>=<value> 當屬性<name> 滿足<value>時觸發
device-added/removed-<patch> 當設備節點添加/刪除時觸發此事件
sevice-exited-<name> 當指定服務<name> 存在時觸發

init.rc中常見的Commands如下:

Command Description
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 中可用的選項如下:

Option Description
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>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章