版權說明:本文爲 開開向前衝 原創文章,轉載請註明出處;
注:限於作者水平有限,文中有不對的地方還請指教。
本文基於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">&</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">&</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">&</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">&</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">&</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">&</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">&</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"><</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">-></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">-></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"><</span>std<span class="token operator">::</span>string<span class="token operator">></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">-></span>sockets<span class="token punctuation">;</span> si<span class="token punctuation">;</span> si <span class="token operator">=</span> si<span class="token operator">-></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">-></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">-></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">-></span>name<span class="token punctuation">,</span> socket_type<span class="token punctuation">,</span>
si<span class="token operator">-></span>perm<span class="token punctuation">,</span> si<span class="token operator">-></span>uid<span class="token punctuation">,</span> si<span class="token operator">-></span>gid<span class="token punctuation">,</span> si<span class="token operator">-></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">>=</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">-></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>