日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

Android init.rc分析

發(fā)布時(shí)間:2025/3/15 Android 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android init.rc分析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1 前言

什么是init.rc文件?

import /init.usb.rc import /init.${ro.hardware}.rc import /init.trace.rcon early-init# Set init and its forked children's oom_adj.write /proc/1/oom_adj -16# Set the security context for the init process.# This should occur before anything else (e.g. ueventd) is started.setcon u:r:init:s0start ueventd# create mountpointsmkdir /mnt 0775 root systemon initsysclktz 0loglevel 3......on fs # mount mtd partitions# Mount /system rw first to give the filesystem a chance to save a checkpointmount yaffs2 mtd@system /systemmount yaffs2 mtd@system /system ro remountmount yaffs2 mtd@userdata /data nosuid nodevmount yaffs2 mtd@cache /cache nosuid nodevon post-fs......on post-fs-data......on boot....... on nonencryptedclass_start late_starton chargerclass_start chargeron property:vold.decrypt=trigger_reset_mainclass_reset main...... service servicemanager /system/bin/servicemanagerclass coreuser systemgroup systemcriticalonrestart restart zygoteonrestart restart mediaonrestart restart surfaceflingeronrestart restart drmservice vold /system/bin/voldclass coresocket vold stream 0660 root mountioprio be 2service netd /system/bin/netdclass mainsocket netd stream 0660 root systemsocket dnsproxyd stream 0660 root inetsocket mdns stream 0660 root systemservice debuggerd /system/bin/debuggerd......

上面的就是一個(gè)init.rc的片段。可以在Android源代碼中找到,位置在/system/core/rootdir/
init.rc是Android系統(tǒng)/init程序讀取的初始化配置文件,用于啟動(dòng)Android中的各種服務(wù),以及配置系統(tǒng)。

2?init.rc分析

文件使用的腳本格式被稱作“Android Init Language”(AIL)
AIL的解析以由空格(Whitespace)分隔的token組成的行為基本單位,這些行由四種類型組成,——Action、Command、Service、Option。

如果一行最開始是"#",那么這一行是注釋。

在/init的main函數(shù)中如下調(diào)用函數(shù)解析該文件:

INFO("reading config file\n"); init_parse_config_file("/init.rc");

函數(shù)init_parse_config_file(/system/core/init/init_parser.c)

int init_parse_config_file(const char *fn) {char *data;data = read_file(fn, 0);if (!data) return -1;parse_config(fn, data);DUMP();return 0; }

該函數(shù)過程如下:

  • 首先調(diào)用函數(shù)read_file(在/system/core/init/util.c中),把/init.rc配置文件讀到data^data變量中,同時(shí)確保文件以“\n \0”結(jié)尾
  • 最后,也是最關(guān)鍵的部分,調(diào)用parse_config函數(shù)進(jìn)行配置文件分析。

為了更好的了解/init.rc的配置究竟是什么,我們必須仔細(xì)分析parse_config函數(shù)。

函數(shù)parse_config(/system/core/init/init_parser.c)

static void parse_config(const char *fn, char *s) {struct parse_state state;struct listnode import_list;struct listnode *node;char *args[INIT_PARSER_MAXARGS];//用于存儲(chǔ)每一行的token字符int nargs;nargs = 0;state.filename = fn;state.line = 0;state.ptr = s;state.nexttoken = 0;state.parse_line = parse_line_no_op;list_init(&import_list);state.priv = &import_list;for (;;) {switch (next_token(&state)) {case T_EOF:state.parse_line(&state, 0, 0);goto parser_done;case T_NEWLINE:state.line++;if (nargs) {int kw = lookup_keyword(args[0]);if (kw_is(kw, SECTION)) {state.parse_line(&state, 0, 0);parse_new_section(&state, kw, nargs, args);} else {state.parse_line(&state, nargs, args);}nargs = 0;}break;case T_TEXT:if (nargs < INIT_PARSER_MAXARGS) {args[nargs++] = state.text;}break;}}parser_done:list_for_each(node, &import_list) {struct import *import = node_to_item(node, struct import, list);int ret;INFO("importing '%s'", import->filename);ret = init_parse_config_file(import->filename);......} }

該函數(shù)有兩個(gè)重要的數(shù)據(jù)結(jié)構(gòu)
struct parse_state定義(/system/core/init/parser.h)

struct parse_state {char *ptr;//文本的指針char *text;//指向解析的單個(gè)tokenint line;//行號(hào)int nexttoken;void *context;//指向不同的數(shù)據(jù)結(jié)構(gòu),表示當(dāng)前正在解析Action或者Service/*處理行的函數(shù),可以證明init.rc的解析是以行為單位的*/void (*parse_line)(struct parse_state *state, int nargs, char **args);const char *filename;//當(dāng)前的文件名void *priv; };

有點(diǎn)編譯原理基礎(chǔ)的就會(huì)明白,這就是parser的狀態(tài)。
還有

char *args[INIT_PARSER_MAXARGS]; int nargs;

在以行單位的解析中,把每一行解析的token字符串指針存放在args字符指針數(shù)組中,把當(dāng)前行中的token個(gè)數(shù)存放在nargs中。

在函數(shù)parse_config中通過switch結(jié)構(gòu)進(jìn)行狀態(tài)的轉(zhuǎn)換。各種狀態(tài)如下。

狀態(tài)解釋
T_EOF代表文件的結(jié)束
T_NEWLINE代表新的一行,所以需要解析當(dāng)前行
T_TEXT代表一個(gè)token,把指針放到對(duì)應(yīng)的args,并更新nargs

重點(diǎn)分析狀態(tài)T_NEWLINE.

case T_NEWLINE:state.line++;if (nargs) {int kw = lookup_keyword(args[0]);if (kw_is(kw, SECTION)) {state.parse_line(&state, 0, 0);parse_new_section(&state, kw, nargs, args);} else {state.parse_line(&state, nargs, args);}nargs = 0;}break;

首先通過lookup_keyworkd和kw_is函數(shù),查找本行的第一個(gè)token是什么類型的,如果是Section,就調(diào)用parse_new_section,否則調(diào)用行處理函數(shù)。

疑問來了,state.parse_line不是在開始賦值為parse_line_no_op的空函數(shù)了嗎?調(diào)用空函數(shù)有什么意義啊?
其實(shí),秘密就在parse_new_section函數(shù)中。我們一步一步來解釋。 首先解決什么是Section,這就需要分析lookup_keyword和kw_is函數(shù)了。

int lookup_keyword(const char *s) {switch (*s++) {case 'c':if (!strcmp(s, "opy")) return K_copy;if (!strcmp(s, "apability")) return K_capability;if (!strcmp(s, "hdir")) return K_chdir;if (!strcmp(s, "hroot")) return K_chroot;......break;case 'd':if (!strcmp(s, "isabled")) return K_disabled;if (!strcmp(s, "omainname")) return K_domainname;break;.......return K_UNKNOWN; }

該函數(shù)根據(jù)字符串返回一一對(duì)應(yīng)的枚舉類型。kw_is是宏:

#define kw_is(kw, type) (keyword_info[kw].flags & (type))

keyword_info是全局變量定義如下:(/system/core/init/keywords.h)

#define KEYWORD(symbol, flags, nargs, func) \[ K_##symbol ] = { #symbol, func, nargs + 1, flags, }, struct {const char *name;int (*func)(int nargs, char **args);unsigned char nargs;unsigned char flags; } keyword_info[KEYWORD_COUNT] = {[ K_UNKNOWN ] = { "unknown", 0, 0, 0 },KEYWORD(capability, OPTION, 0, 0)KEYWORD(chdir, COMMAND, 1, do_chdir)KEYWORD(chroot, COMMAND, 1, do_chroot)KEYWORD(class, OPTION, 0, 0)KEYWORD(class_start, COMMAND, 1, do_class_start)KEYWORD(class_stop, COMMAND, 1, do_class_stop)KEYWORD(class_reset, COMMAND, 1, do_class_reset)KEYWORD(console, OPTION, 0, 0)KEYWORD(critical, OPTION, 0, 0)KEYWORD(disabled, OPTION, 0, 0)KEYWORD(domainname, COMMAND, 1, do_domainname)KEYWORD(exec, COMMAND, 1, do_exec)KEYWORD(export, COMMAND, 2, do_export)KEYWORD(group, OPTION, 0, 0)KEYWORD(hostname, COMMAND, 1, do_hostname)KEYWORD(ifup, COMMAND, 1, do_ifup)KEYWORD(insmod, COMMAND, 1, do_insmod)KEYWORD(import, SECTION, 1, 0)KEYWORD(keycodes, OPTION, 0, 0)KEYWORD(mkdir, COMMAND, 1, do_mkdir)KEYWORD(mount_all, COMMAND, 1, do_mount_all)KEYWORD(mount, COMMAND, 3, do_mount)KEYWORD(on, SECTION, 0, 0)KEYWORD(oneshot, OPTION, 0, 0)KEYWORD(onrestart, OPTION, 0, 0)KEYWORD(restart, COMMAND, 1, do_restart)KEYWORD(restorecon, COMMAND, 1, do_restorecon)KEYWORD(rm, COMMAND, 1, do_rm)KEYWORD(rmdir, COMMAND, 1, do_rmdir)KEYWORD(seclabel, OPTION, 0, 0)KEYWORD(service, SECTION, 0, 0)KEYWORD(setcon, COMMAND, 1, do_setcon)KEYWORD(setenforce, COMMAND, 1, do_setenforce)KEYWORD(setenv, OPTION, 2, 0)KEYWORD(setkey, COMMAND, 0, do_setkey)KEYWORD(setprop, COMMAND, 2, do_setprop)KEYWORD(setrlimit, COMMAND, 3, do_setrlimit)KEYWORD(setsebool, COMMAND, 1, do_setsebool)KEYWORD(socket, OPTION, 0, 0)KEYWORD(start, COMMAND, 1, do_start)KEYWORD(stop, COMMAND, 1, do_stop)KEYWORD(trigger, COMMAND, 1, do_trigger)KEYWORD(symlink, COMMAND, 1, do_symlink)KEYWORD(sysclktz, COMMAND, 1, do_sysclktz)KEYWORD(user, OPTION, 0, 0)KEYWORD(wait, COMMAND, 1, do_wait)KEYWORD(write, COMMAND, 2, do_write)KEYWORD(copy, COMMAND, 2, do_copy)KEYWORD(chown, COMMAND, 2, do_chown)KEYWORD(chmod, COMMAND, 2, do_chmod)KEYWORD(loglevel, COMMAND, 1, do_loglevel)KEYWORD(load_persist_props, COMMAND, 0, do_load_persist_props)KEYWORD(ioprio, OPTION, 0, 0) };

關(guān)鍵字import、on、service代表新的Section的開始。 所以init.rc文件的結(jié)構(gòu)如下:

  • 最高層由Section組成,分為trigger、import、service,分別以on,?import,service關(guān)鍵字開頭。
  • importSection只有一行,至于載入其他rc文件
  • triggerSection由?Command組成。
  • serviceSection有?Option組成。

接下來我們直擊核心函數(shù)parse_new_section

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:state->context = parse_service(state, nargs, args);if (state->context) {state->parse_line = parse_line_service;return;}break;case K_on:state->context = parse_action(state, nargs, args);if (state->context) {state->parse_line = parse_line_action;return;}break;case K_import:parse_import(state, nargs, args);break;}state->parse_line = parse_line_no_op; }

在該函數(shù)中可以明顯看到Section的種類,以及state.parse_line被更改。接下來我們按Section種類,分三部分分析。
但是在這之前先介紹三個(gè)數(shù)據(jù)結(jié)構(gòu):

static list_declare(service_list); static list_declare(action_list); static list_declare(action_queue);

這三個(gè)全局變量都是鏈表的表頭,是/init對(duì)/init.rc解析所要操作的關(guān)鍵函數(shù),也可以說是解析的目的所在。service_list代表解析得到的Service,action_list代表解析得到的Action,action_queue代表將要執(zhí)行的Action隊(duì)列。
/init可以認(rèn)為主要是做了如下工作:

  • 解析/init.rc,把得到的Action和?Service連接到action_list和service_list中。
  • 內(nèi)部或者外部出發(fā)trigger把對(duì)應(yīng)的Action連接到action_queue。
  • 在for循環(huán)中依次執(zhí)行action_queue隊(duì)列中Action對(duì)應(yīng)的Command
  • Section Serivice

    每個(gè)Service,由一個(gè)struct service數(shù)據(jù)結(jié)構(gòu)代表,定義如下:

    struct service {/* list of all services */struct listnode slist;//連接到service_listconst char *name;const char *classname;unsigned flags;pid_t pid;time_t time_started; /* time of last start */time_t time_crashed; /* first crash within inspection window */int nr_crashed; /* number of times crashed within window */uid_t uid;gid_t gid;gid_t supp_gids[NR_SVC_SUPP_GIDS];size_t nr_supp_gids;#ifdef HAVE_SELINUXchar *seclabel; #endifstruct socketinfo *sockets;struct svcenvinfo *envvars;struct action onrestart; /* Actions to execute on restart. *//* keycodes for triggering this service via /dev/keychord */int *keycodes;int nkeycodes;int keychord_id;int ioprio_class;int ioprio_pri;int nargs;/* "MUST BE AT THE END OF THE STRUCT" */char *args[1]; }; /* ^-------'args' MUST be at the end of thi

    函數(shù)parse_service(/system/core/init/init_parser.c)

    static void *parse_service(struct parse_state *state, int nargs, char **args) {struct service *svc;if (nargs < 3) {parse_error(state, "services must have a name and a program\n");return 0;}if (!valid_name(args[1])) {parse_error(state, "invalid service name '%s'\n", args[1]);return 0;}svc = service_find_by_name(args[1]);if (svc) {parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);return 0;}nargs -= 2;svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs);if (!svc) {parse_error(state, "out of memory\n");return 0;}svc->name = args[1];svc->classname = "default";memcpy(svc->args, args + 2, sizeof(char*) * nargs);svc->args[nargs] = 0;svc->nargs = nargs;svc->onrestart.name = "onrestart";list_init(&svc->onrestart.commands);list_add_tail(&service_list, &svc->slist);return svc; }

    首先本Section的第一行必須是如下格式

    service <service name> <program name>

    而且在valid_name函數(shù)中規(guī)定,service name必須不超過16個(gè)字符,而且只能由字母、數(shù)字、“-”、“_”組成。

    當(dāng)出現(xiàn)重名的service時(shí),會(huì)被忽略。

    最后把Service掛到service_list尾部

    下面分析parse_line_service函數(shù)

    static void parse_line_service(struct parse_state *state, int nargs, char **args) {struct service *svc = state->context;struct command *cmd;int i, kw, kw_nargs;if (nargs == 0) {return;}svc->ioprio_class = IoSchedClass_NONE;kw = lookup_keyword(args[0]);switch (kw) {case K_capability:break;case K_class:if (nargs != 2) {parse_error(state, "class option requires a classname\n");} else {svc->classname = args[1];}break;case K_console:svc->flags |= SVC_CONSOLE;break;case K_disabled:svc->flags |= SVC_DISABLED;svc->flags |= SVC_RC_DISABLED;break;case K_ioprio:if (nargs != 3) {parse_error(state, "ioprio optin usage: ioprio <rt|be|idle> <ioprio 0-7>\n");} else {svc->ioprio_pri = strtoul(args[2], 0, 8);if (svc->ioprio_pri < 0 || svc->ioprio_pri > 7) {parse_error(state, "priority value must be range 0 - 7\n");break;}if (!strcmp(args[1], "rt")) {svc->ioprio_class = IoSchedClass_RT;} else if (!strcmp(args[1], "be")) {svc->ioprio_class = IoSchedClass_BE;} else if (!strcmp(args[1], "idle")) {svc->ioprio_class = IoSchedClass_IDLE;} else {parse_error(state, "ioprio option usage: ioprio <rt|be|idle> <0-7>\n");}}break;case K_group:if (nargs < 2) {parse_error(state, "group option requires a group id\n");} else if (nargs > NR_SVC_SUPP_GIDS + 2) {parse_error(state, "group option accepts at most %d supp. groups\n",NR_SVC_SUPP_GIDS);} else {int n;svc->gid = decode_uid(args[1]);for (n = 2; n < nargs; n++) {svc->supp_gids[n-2] = decode_uid(args[n]);}svc->nr_supp_gids = n - 2;}break;case K_keycodes:if (nargs < 2) {parse_error(state, "keycodes option requires atleast one keycode\n");} else {svc->keycodes = malloc((nargs - 1) * sizeof(svc->keycodes[0]));if (!svc->keycodes) {parse_error(state, "could not allocate keycodes\n");} else {svc->nkeycodes = nargs - 1;for (i = 1; i < nargs; i++) {svc->keycodes[i - 1] = atoi(args[i]);}}}break;case K_oneshot:svc->flags |= SVC_ONESHOT;break;case K_onrestart:nargs--;args++;kw = lookup_keyword(args[0]);if (!kw_is(kw, COMMAND)) {parse_error(state, "invalid command '%s'\n", args[0]);break;}kw_nargs = kw_nargs(kw);if (nargs < kw_nargs) {parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,kw_nargs > 2 ? "arguments" : "argument");break;}cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);cmd->func = kw_func(kw);cmd->nargs = nargs;memcpy(cmd->args, args, sizeof(char*) * nargs);list_add_tail(&svc->onrestart.commands, &cmd->clist);break;case K_critical:svc->flags |= SVC_CRITICAL;break;case K_setenv: { /* name value */struct svcenvinfo *ei;if (nargs < 2) {parse_error(state, "setenv option requires name and value arguments\n");break;}ei = calloc(1, sizeof(*ei));if (!ei) {parse_error(state, "out of memory\n");break;}ei->name = args[1];ei->value = args[2];ei->next = svc->envvars;svc->envvars = ei;break;}case K_socket: {/* name type perm [ uid gid ] */struct socketinfo *si;if (nargs < 4) {parse_error(state, "socket option requires name, type, perm arguments\n");break;}if (strcmp(args[2],"dgram") && strcmp(args[2],"stream")&& strcmp(args[2],"seqpacket")) {parse_error(state, "socket type must be 'dgram', 'stream' or 'seqpacket'\n");break;}si = calloc(1, sizeof(*si));if (!si) {parse_error(state, "out of memory\n");break;}si->name = args[1];si->type = args[2];si->perm = strtoul(args[3], 0, 8);if (nargs > 4)si->uid = decode_uid(args[4]);if (nargs > 5)si->gid = decode_uid(args[5]);si->next = svc->sockets;svc->sockets = si;break;}case K_user:if (nargs != 2) {parse_error(state, "user option requires a user id\n");} else {svc->uid = decode_uid(args[1]);}break;case K_seclabel: #ifdef HAVE_SELINUXif (nargs != 2) {parse_error(state, "seclabel option requires a label string\n");} else {svc->seclabel = args[1];} #endifbreak;default:parse_error(state, "invalid option '%s'\n", args[0]);} }

    該函數(shù)就是對(duì)ServiceOption進(jìn)行解析,并把相應(yīng)的struct service的字段賦值。

    ServicesOption是服務(wù)的修飾符,可以影響服務(wù)如何以及怎樣運(yùn)行。服務(wù)支持的選項(xiàng)如下:

    1. critical

    表明這是一個(gè)非常重要的服務(wù)。如果該服務(wù)4分鐘內(nèi)退出大于4次,系統(tǒng)將會(huì)重啟并進(jìn)入 Recovery (恢復(fù))模式。

    2. disabled

    表明這個(gè)服務(wù)不會(huì)同與他同trigger (觸發(fā)器)下的服務(wù)自動(dòng)啟動(dòng)。該服務(wù)必須被明確的按名啟動(dòng)。必須通過start <service name>Command,class_start <class_name>Command不能啟動(dòng)即使該服務(wù)在

    3. setenv <name> <value>

    在進(jìn)程啟動(dòng)時(shí)將環(huán)境變量設(shè)置為。

    4. socket <name> <type> <perm> [ <user> [ <group> ] ]

    創(chuàng)建一個(gè)unix域的名為/dev/socket/?的套接字,并傳遞它的文件描述符給已啟動(dòng)的進(jìn)程。?必須是 "dgram","stream" 或"seqpacket"。用戶和組默認(rèn)是0。

    5. user <username>

    在啟動(dòng)這個(gè)服務(wù)前改變?cè)摲?wù)的用戶名。此時(shí)默認(rèn)為 root。

    6. group <groupname> [<groupname> ]*

    在啟動(dòng)這個(gè)服務(wù)前改變?cè)摲?wù)的組名。除了(必需的)第一個(gè)組名,附加的組名通常被用于設(shè)置進(jìn)程的補(bǔ)充組(通過setgroups函數(shù)),檔案默認(rèn)是root。

    7. oneshot

    服務(wù)退出時(shí)不重啟。

    8. class <name>

    指定一個(gè)服務(wù)類。所有同一類的服務(wù)可以同時(shí)啟動(dòng)和停止。如果不通過class選項(xiàng)指定一個(gè)類,則默認(rèn)為"default"類服務(wù)。

    9. onrestart

    當(dāng)服務(wù)重啟,執(zhí)行一個(gè)命令。

    Section Action

    每個(gè)Action以及包含的Command由如下數(shù)據(jù)結(jié)構(gòu)表示:

    struct command {/* list of commands in an action */struct listnode clist;int (*func)(int nargs, char **args);int nargs;char *args[1]; };struct action {/* node in list of all actions */struct listnode alist;//連接到action_list/* node in the queue of pending actions */struct listnode qlist;//連接到action_queue/* node in list of actions for a trigger */struct listnode tlist;unsigned hash;const char *name;struct listnode commands;//包含command的鏈表表頭struct command *current; };

    函數(shù)parse_action(/system/core/init/init_parser.c)

    static void *parse_action(struct parse_state *state, int nargs, char **args) {struct action *act;if (nargs < 2) {parse_error(state, "actions must have a trigger\n");return 0;}if (nargs > 2) {parse_error(state, "actions may not have extra parameters\n");return 0;}act = calloc(1, sizeof(*act));act->name = args[1];list_init(&act->commands);list_add_tail(&action_list, &act->alist);/* XXX add to hash */return act; }

    首先本Section的第一行必須是如下格式

    on <trigger name>

    最后把Action掛到action_list尾部。可以看到似乎打算把Action加到hash表中但是還沒有實(shí)現(xiàn)。

    下面分析parse_line_action函數(shù)

    static void parse_line_action(struct parse_state* state, int nargs, char **args) {struct command *cmd;struct action *act = state->context;int (*func)(int nargs, char **args);int kw, n;if (nargs == 0) {return;}kw = lookup_keyword(args[0]);if (!kw_is(kw, COMMAND)) {parse_error(state, "invalid command '%s'\n", args[0]);return;}n = kw_nargs(kw);if (nargs < n) {parse_error(state, "%s requires %d %s\n", args[0], n - 1,n > 2 ? "arguments" : "argument");return;}cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);cmd->func = kw_func(kw);cmd->nargs = nargs;memcpy(cmd->args, args, sizeof(char*) * nargs);list_add_tail(&act->commands, &cmd->clist); }

    Actions后需要跟若干個(gè)命令,這些命令如下:

    1. exec <path> [<argument> ]*

    創(chuàng)建和執(zhí)行一個(gè)程序(<path>)。在程序完全執(zhí)行前,init將會(huì)阻塞。由于它不是內(nèi)置命令,應(yīng)盡量避免使用exec ,它可能會(huì)引起init執(zhí)行超時(shí)。

    2. export <name> <value>

    在全局環(huán)境中將<name>變量的值設(shè)為<value>。(這將會(huì)被所有在這命令之后運(yùn)行的進(jìn)程所繼承)

    3. ifup <interface>

    啟動(dòng)網(wǎng)絡(luò)接口

    4. import <filename>

    指定要解析的其他配置文件。常被用于當(dāng)前配置文件的擴(kuò)展

    5. hostname <name>

    設(shè)置主機(jī)名

    6. chdir <directory>

    改變工作目錄

    7. chmod <octal-mode><path>

    改變文件的訪問權(quán)限

    8. chown <owner><group> <path>

    更改文件的所有者和組

    9. chroot <directory>

    改變處理根目錄

    10. class_start<serviceclass>

    啟動(dòng)所有指定服務(wù)類下的未運(yùn)行服務(wù)。

    11 class_stop<serviceclass>

    停止指定服務(wù)類下的所有已運(yùn)行的服務(wù)。

    12. domainname <name>

    設(shè)置域名

    13. insmod <path>

    加載path指定的驅(qū)動(dòng)模塊

    14. mkdir <path> [mode][owner] [group]

    創(chuàng)建一個(gè)目錄<path>?,可以選擇性地指定mode、owner以及group。如果沒有指定,默認(rèn)的權(quán)限為755,并屬于root用戶和 root組。

    15. mount <type> <device> <dir> [<mountoption> ]*

    試圖在目錄<dir>掛載指定的設(shè)備。<device>?可以是mtd@name的形式指定一個(gè)mtd塊設(shè)備。<mountoption>包括 "ro"、"rw"、"re

    16. setkey

    保留,暫時(shí)未用

    17. setprop <name><value>

    將系統(tǒng)屬性<name>的值設(shè)為<value>。

    18. setrlimit <resource> <cur> <max>

    設(shè)置<resource>的rlimit (資源限制)

    19. start <service>

    啟動(dòng)指定服務(wù)(如果此服務(wù)還未運(yùn)行)。

    20.stop<service>

    停止指定服務(wù)(如果此服務(wù)在運(yùn)行中)。

    21. symlink <target> <path>

    創(chuàng)建一個(gè)指向<path>的軟連接<target>。

    22. sysclktz <mins_west_of_gmt>

    設(shè)置系統(tǒng)時(shí)鐘基準(zhǔn)(0代表時(shí)鐘滴答以格林威治平均時(shí)(GMT)為準(zhǔn))

    23. trigger <event>

    觸發(fā)一個(gè)事件。用于Action排隊(duì)

    24. wait <path> [<timeout> ]

    等待一個(gè)文件是否存在,當(dāng)文件存在時(shí)立即返回,或到指定的超時(shí)時(shí)間后返回,如果不指定,默認(rèn)超時(shí)時(shí)間是5秒。

    25. write <path> <string> [ <string> ]*

    向<path>指定的文件寫入一個(gè)或多個(gè)字符串。

    Section Import

    每個(gè)Import由如下數(shù)據(jù)結(jié)構(gòu)表示:

    struct import {struct listnode list;const char *filename; };void parse_import(struct parse_state *state, int nargs, char **args) {struct listnode *import_list = state->priv;struct import *import;char conf_file[PATH_MAX];int ret;if (nargs != 2) {ERROR("single argument needed for import\n");return;}ret = expand_props(conf_file, args[1], sizeof(conf_file));if (ret) {ERROR("error while handling import on line '%d' in '%s'\n",state->line, state->filename);return;}import = calloc(1, sizeof(struct import));import->filename = strdup(conf_file);list_add_tail(import_list, &import->list);INFO("found import '%s', adding to import list", import->filename); }

    函數(shù)expand_props把配置文件中的${<property_name>},通過Property System讀取對(duì)應(yīng)的值。通常要讀取ro.machine和ro.arch的值,展開后形成真正的文件名,然后掛載在state.priv上。

    在parse_config函數(shù)的末尾,有如下代碼:

    parser_done:list_for_each(node, &import_list) {struct import *import = node_to_item(node, struct import, list);int ret;INFO("importing '%s'", import->filename);ret = init_parse_config_file(import->filename);

    實(shí)現(xiàn)了對(duì)import進(jìn)的文件的解析。

    總結(jié)

    以上是生活随笔為你收集整理的Android init.rc分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。