1. 程式人生 > >Android uevent程序原始碼分析

Android uevent程序原始碼分析

Android Init程序原始碼分析中講到init程序會依次執行被加入到待執行佇列action_queue中的Action,在init.rc中我們有這麼一段配置:

[plain] view plaincopyprint?
  1. 11 on early-init  
  2. 12     # Set init and its forked children's oom_adj.  
  3. 13     write /proc/1/oom_adj -16  
  4. 14   
  5. 15     start ueventd  
  6. 16   
  7. 17 # create mountpoints  
  8. 18     mkdir /mnt 0775 root system  
 11 on early-init
 12     # Set init and its forked children's oom_adj.
 13     write /proc/1/oom_adj -16
 14 
 15     start ueventd
 16 
 17 # create mountpoints
 18     mkdir /mnt 0775 root system
對於early-init 這個section 在Android Init程序原始碼分析一文中已經介紹了在解析完init.rc檔案後被新增到了action_queue佇列 [cpp] view plain
copyprint?
  1. action_for_each_trigger("early-init", action_add_queue_tail);  
action_for_each_trigger("early-init", action_add_queue_tail);
因此Init程序會首先啟動ueventd程序,關鍵字start用於啟動一個服務程序,該關鍵字對應的執行函式為: [cpp] view plaincopyprint?
  1. KEYWORD(start,       COMMAND, 1, do_start)  
KEYWORD(start,       COMMAND, 1, do_start)
在解析命令列時,被新增到Action的commands連結串列中: [cpp] view plaincopyprint?
  1. cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);  
  2. cmd->func = kw_func(kw);  
  3. cmd->nargs = nargs;  
  4. memcpy(cmd->args, args, sizeof(char*) * nargs);  
  5. list_add_tail(&act->commands, &cmd->clist);  
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);

ueventd程序的執行程式碼和Init程序的執行程式碼被編譯到了同一個可執行程式Init中了,通過檢視Android.mk檔案即可以得到證實:

[cpp] view plaincopyprint?
  1. LOCAL_SRC_FILES:= \  
  2.     builtins.c \  
  3.     init.c \  
  4.     devices.c \  
  5.     property_service.c \  
  6.     util.c \  
  7.     parser.c \  
  8.     logo.c \  
  9.     keychords.c \  
  10.     signal_handler.c \  
  11.     init_parser.c \  
  12.     ueventd.c \  
  13.     ueventd_parser.c  
  14. ifeq ($(strip $(INIT_BOOTCHART)),true)  
  15. LOCAL_SRC_FILES += bootchart.c  
  16. LOCAL_CFLAGS    += -DBOOTCHART=1  
  17. endif  
  18. ifeq ($(BOARD_HAVE_BLUETOOTH_BCM),true)  
  19. LOCAL_CFLAGS += \  
  20.     -DBOARD_HAVE_BLUETOOTH_BCM  
  21. endif  
  22. ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))  
  23. LOCAL_CFLAGS += -DALLOW_LOCAL_PROP_OVERRIDE=1  
  24. endif  
  25. LOCAL_MODULE:= init  
  26. LOCAL_FORCE_STATIC_EXECUTABLE := true
  27. LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)  
  28. LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)  
  29. LOCAL_STATIC_LIBRARIES := libfs_mgr libcutils libc  
  30. ifeq ($(HAVE_SELINUX),true)  
  31. LOCAL_STATIC_LIBRARIES += libselinux  
  32. LOCAL_C_INCLUDES += external/libselinux/include  
  33. LOCAL_CFLAGS += -DHAVE_SELINUX  
  34. endif  
  35. include $(BUILD_EXECUTABLE)  
  36. # Make a symlink from /sbin/ueventd to /init
  37. SYMLINKS := $(TARGET_ROOT_OUT)/sbin/ueventd  
  38. $(SYMLINKS): INIT_BINARY := $(LOCAL_MODULE)  
  39. $(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk  
  40.     @echo "Symlink: [email protected] -> ../$(INIT_BINARY)"
  41.     @mkdir -p $(dir [email protected])  
  42.     @rm -rf [email protected]  
  43.     $(hide) ln -sf ../$(INIT_BINARY) [email protected]  
  44. ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS)  
LOCAL_SRC_FILES:= \
	builtins.c \
	init.c \
	devices.c \
	property_service.c \
	util.c \
	parser.c \
	logo.c \
	keychords.c \
	signal_handler.c \
	init_parser.c \
	ueventd.c \
	ueventd_parser.c

ifeq ($(strip $(INIT_BOOTCHART)),true)
LOCAL_SRC_FILES += bootchart.c
LOCAL_CFLAGS    += -DBOOTCHART=1
endif

ifeq ($(BOARD_HAVE_BLUETOOTH_BCM),true)
LOCAL_CFLAGS += \
	-DBOARD_HAVE_BLUETOOTH_BCM
endif

ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
LOCAL_CFLAGS += -DALLOW_LOCAL_PROP_OVERRIDE=1
endif

LOCAL_MODULE:= init

LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)

LOCAL_STATIC_LIBRARIES := libfs_mgr libcutils libc

ifeq ($(HAVE_SELINUX),true)
LOCAL_STATIC_LIBRARIES += libselinux
LOCAL_C_INCLUDES += external/libselinux/include
LOCAL_CFLAGS += -DHAVE_SELINUX
endif

include $(BUILD_EXECUTABLE)

# Make a symlink from /sbin/ueventd to /init
SYMLINKS := $(TARGET_ROOT_OUT)/sbin/ueventd
$(SYMLINKS): INIT_BINARY := $(LOCAL_MODULE)
$(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk
	@echo "Symlink: [email protected] -> ../$(INIT_BINARY)"
	@mkdir -p $(dir [email protected])
	@rm -rf [email protected]
	$(hide) ln -sf ../$(INIT_BINARY) [email protected]

ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS)
uevent以軟連結的方式連結到了Init可執行程式,通過檢視手機中的uevent程式可知:

因為ueventd 和 Init 在同一個可執行檔案下,因此在啟動ueventd程序時,程序入口函式依然是system\core\init\init.c檔案中的main函式:

[cpp] view plaincopyprint?
  1. int main(int argc, char **argv)  
  2. {  
  3. int fd_count = 0;  
  4. struct pollfd ufds[4];  
  5. char *tmpdev;  
  6. char* debuggable;  
  7. char tmp[32];  
  8. int property_set_fd_init = 0;  
  9. int signal_fd_init = 0;  
  10. int keychord_fd_init = 0;  
  11. bool is_charger = false;  
  12. if (!strcmp(basename(argv[0]), "ueventd"))  
  13. return ueventd_main(argc, argv);  
  14.     .....  
  15. }  
int main(int argc, char **argv)
{
    int fd_count = 0;
    struct pollfd ufds[4];
    char *tmpdev;
    char* debuggable;
    char tmp[32];
    int property_set_fd_init = 0;
    int signal_fd_init = 0;
    int keychord_fd_init = 0;
    bool is_charger = false;

    if (!strcmp(basename(argv[0]), "ueventd"))
        return ueventd_main(argc, argv);

	.....
}

basename 函式從啟動的程式路徑下擷取應用名稱,如果啟動的應用為ueventd程序,則跳轉到ueventd_main函式作為應用的入口函式:

[cpp] view plaincopyprint?
  1. int ueventd_main(int argc, char **argv)  
  2. {  
  3. struct pollfd ufd;  
  4. int nr;  
  5. char tmp[32];  
  6. /* 
  7.      * init sets the umask to 077 for forked processes. We need to 
  8.      * create files with exact permissions, without modification by 
  9.      * the umask. 
  10.      */
  11.     umask(000);  
  12. /* Prevent fire-and-forget children from becoming zombies. 
  13.      * If we should need to wait() for some children in the future 
  14.      * (as opposed to none right now), double-forking here instead 
  15.      * of ignoring SIGCHLD may be the better solution. 
  16.      */
  17.     signal(SIGCHLD, SIG_IGN);  
  18.     open_devnull_stdio();  
  19.     klog_init();  
  20.     INFO("starting ueventd\n");  
  21. /* Respect hardware passed in through the kernel cmd line. Here we will look 
  22.      * for androidboot.hardware param in kernel cmdline, and save its value in 
  23.      * hardware[]. */
  24.     import_kernel_cmdline(0, import_kernel_nv);  
  25.     get_hardware_name(hardware, &revision);  
  26. //解析ueventd.rc配置檔案
  27.     ueventd_parse_config_file("/ueventd.rc");  
  28. //解析ueventd.xxx.rc 配置檔案
  29.     snprintf(tmp, sizeof(tmp), "/ueventd.%s.rc", hardware);  
  30.     ueventd_parse_config_file(tmp);  
  31. //裝置節點初始化
  32.     device_init();  
  33.     ufd.events = POLLIN;  
  34.     ufd.fd = get_device_fd();  
  35. //進入閉環監控模式
  36. while(1) {   
  37.         ufd.revents = 0;  
  38. //監控uevent socket的連線,引數為-1表示無限超時,在沒有事件發生時函式阻塞監控
  39.         nr = poll(&ufd, 1, -1);  
  40. if (nr <= 0)  
  41. continue;  
  42. if (ufd.revents == POLLIN)  
  43. //裝置事件處理
  44.                handle_device_fd();  
  45.     }  
  46. }  
int ueventd_main(int argc, char **argv)
{
    struct pollfd ufd;
    int nr;
    char tmp[32];

    /*
     * init sets the umask to 077 for forked processes. We need to
     * create files with exact permissions, without modification by
     * the umask.
     */
    umask(000);

    /* Prevent fire-and-forget children from becoming zombies.
     * If we should need to wait() for some children in the future
     * (as opposed to none right now), double-forking here instead
     * of ignoring SIGCHLD may be the better solution.
     */
    signal(SIGCHLD, SIG_IGN);

    open_devnull_stdio();
    klog_init();

    INFO("starting ueventd\n");

    /* Respect hardware passed in through the kernel cmd line. Here we will look
     * for androidboot.hardware param in kernel cmdline, and save its value in
     * hardware[]. */
    import_kernel_cmdline(0, import_kernel_nv);

    get_hardware_name(hardware, &revision);
    //解析ueventd.rc配置檔案
    ueventd_parse_config_file("/ueventd.rc");
    //解析ueventd.xxx.rc 配置檔案
    snprintf(tmp, sizeof(tmp), "/ueventd.%s.rc", hardware);
    ueventd_parse_config_file(tmp);
    //裝置節點初始化
    device_init();
    
    ufd.events = POLLIN;
    ufd.fd = get_device_fd();
    //進入閉環監控模式
    while(1) { 
        ufd.revents = 0;
		//監控uevent socket的連線,引數為-1表示無限超時,在沒有事件發生時函式阻塞監控
        nr = poll(&ufd, 1, -1);
        if (nr <= 0)
            continue;
        if (ufd.revents == POLLIN)
			   //裝置事件處理
               handle_device_fd();
    }
}
該函式前面幾個步驟和init程序基本相同,這裡就不在詳細介紹了,可參考Android Init程序原始碼分析,在初始化完標準輸入輸出、log、匯入命令列引數後,將解析uevent.rc檔案和一個同硬體特定硬體相關的ueventd.XXX.rc檔案,ueventd.rc檔案內容如下所示: [plain] view plaincopyprint?
  1. /dev/null                 0666   root       root  
  2. /dev/zero                 0666   root       root  
  3. /dev/full                 0666   root       root  
  4. /dev/ptmx                 0666   root       root  
  5. /dev/tty                  0666   root       root  
  6. /dev/random               0666   root       root  
  7. /dev/urandom              0666   root       root  
  8. /dev/ashmem               0666   root       root  
  9. /dev/binder               0666   root       root  
  10. # Anyone can read the logs, but if they're not in the "logs"  
  11. # group, then they'll only see log entries for their UID.  
  12. /dev/log/*                0666   root       log  
  13. # the msm hw3d client device node is world writable/readable.  
  14. /dev/msm_hw3dc            0666   root       root  
  15. # gpu driver for adreno200 is globally accessible  
  16. /dev/kgsl                 0666   root       root  
  17. # these should not be world writable  
  18. /dev/diag                 0660   radio      radio  
  19. /dev/diag_arm9            0660   radio      radio  
  20. /dev/android_adb          0660   adb        adb  
  21. /dev/android_adb_enable   0660   adb        adb  
  22. /dev/ttyMSM0              0600   bluetooth  bluetooth  
  23. /dev/uinput               0660   system     bluetooth  
/dev/null                 0666   root       root
/dev/zero                 0666   root       root
/dev/full                 0666   root       root
/dev/ptmx                 0666   root       root
/dev/tty                  0666   root       root
/dev/random               0666   root       root
/dev/urandom              0666   root       root
/dev/ashmem               0666   root       root
/dev/binder               0666   root       root

# Anyone can read the logs, but if they're not in the "logs"
# group, then they'll only see log entries for their UID.
/dev/log/*                0666   root       log

# the msm hw3d client device node is world writable/readable.
/dev/msm_hw3dc            0666   root       root

# gpu driver for adreno200 is globally accessible
/dev/kgsl                 0666   root       root

# these should not be world writable
/dev/diag                 0660   radio      radio
/dev/diag_arm9            0660   radio      radio
/dev/android_adb          0660   adb        adb
/dev/android_adb_enable   0660   adb        adb
/dev/ttyMSM0              0600   bluetooth  bluetooth
/dev/uinput               0660   system     bluetooth

在system\core\init\ueventd.c檔案中,使用ueventd_parse_config_file函式來對ueventd.rc進行解析,接下來詳細分析整個解析過程:

[cpp] view plaincopyprint?
  1. int ueventd_parse_config_file(constchar *fn)  
  2. {  
  3. char *data;  
  4. //讀取檔案內容
  5.     data = read_file(fn, 0);  
  6. if (!data) return -1;  
  7. //解析整個rc檔案內容
  8.     parse_config(fn, data);  
  9.     DUMP();  
  10. return 0;  
  11. }  
int ueventd_parse_config_file(const char *fn)
{
    char *data;
	//讀取檔案內容
    data = read_file(fn, 0);
    if (!data) return -1;
    //解析整個rc檔案內容
    parse_config(fn, data);
    DUMP();
    return 0;
}

以上步驟和Init程序解析init.rc檔案的步驟相同,不過這裡呼叫的parse_config函式不同,該函式是專門用於解析ueventd.rc檔案的,具體解析過程如下:

[cpp] view plaincopyprint?
  1. staticvoid parse_config(constchar *fn, char *s)  
  2. {  
  3. struct parse_state state;  
  4. char *args[UEVENTD_PARSER_MAXARGS];  
  5. int nargs;  
  6.     nargs = 0;  
  7.     state.filename = fn; //設定解析檔案的路徑
  8.     state.line = 1;  
  9.     state.ptr = s;//檔案內容
  10.     state.nexttoken = 0;  
  11.     state.parse_line = parse_line_device; //設定每行解析回撥函式
  12. for (;;) {  
  13. //從檔案內容中查詢token,與init.rc檔案類似
  14. int token = next_token(&state);   
  15. switch (token) {  
  16. //檔案結束
  17. case T_EOF:  
  18.             state.parse_line(&state, 0, 0);  
  19. return;  
  20. //新的一行
  21. case T_NEWLINE:  
  22. if (nargs) {  
  23. //呼叫行解析函式解析每一行
  24.                 state.parse_line(&state, nargs, args);  
  25.                 nargs = 0;  
  26.             }  
  27. break;  
  28. case T_TEXT:  
  29. if (nargs < UEVENTD_PARSER_MAXARGS) {  
  30.                 args[nargs++] = state.text;  
  31.             }  
  32. break;  
  33.         }  
  34.     }  
  35. }  
static void parse_config(const char *fn, char *s)
{
    struct parse_state state;
    char *args[UEVENTD_PARSER_MAXARGS];
    int nargs;
    nargs = 0;
    state.filename = fn; //設定解析檔案的路徑
    state.line = 1;
    state.ptr = s;//檔案內容
    state.nexttoken = 0;
    state.parse_line = parse_line_device; //設定每行解析回撥函式
    for (;;) {
		//從檔案內容中查詢token,與init.rc檔案類似
        int token = next_token(&state); 
        switch (token) {
		//檔案結束
        case T_EOF:
            state.parse_line(&state, 0, 0);
            return;
		//新的一行
        case T_NEWLINE:
            if (nargs) {
			    //呼叫行解析函式解析每一行
                state.parse_line(&state, nargs, args);
                nargs = 0;
            }
            break;
        case T_TEXT:
            if (nargs < UEVENTD_PARSER_MAXARGS) {
                args[nargs++] = state.text;
            }
            break;
        }
    }
}

函式首先查詢指定的token,然後對不同的token做不同的處理,對於發現新行時,呼叫parse_line_device函式對每一行進行詳細解析,該函式實現如下:

[cpp] view plaincopyprint?
  1. staticvoid parse_line_device(struct parse_state* state, int nargs, char **args)  
  2. {  
  3.     set_device_permission(nargs, args);  
  4. }  
static void parse_line_device(struct parse_state* state, int nargs, char **args)
{
    set_device_permission(nargs, args);
}

函式直接呼叫set_device_permission來實現,ueventd.rc檔案每一行的書寫規則為:

非sysfs 裝置檔案:

|name|  |permission| |user| |group|

/dev/cam   0660   root       ca

sysfs 裝置檔案屬性:
/sys/devices/virtual/input/input*   enable      0660  root   input

[cpp] view plaincopyprint?
  1. void set_device_permission(int nargs, char **args)  
  2. {  
  3. char *name;  
  4. char *attr = 0;  
  5.     mode_t perm;  
  6.     uid_t uid;  
  7.     gid_t gid;  
  8. int prefix = 0;  
  9. char *endptr;  
  10. int ret;  
  11. char *tmp = 0;  
  12. if (nargs == 0)  
  13. return;  
  14. if (args[0][0] == '#')  
  15. return;  
  16. /*  |name|  |permission| |user| |group|  */
  17.     name = args[0];  
  18. if (!strncmp(name,"/sys/", 5) && (nargs == 5)) {  
  19.         INFO("/sys/ rule %s %s\n",args[0],args[1]);  
  20.         attr = args[1];  
  21.         args++;  
  22.         nargs--;  
  23.     }  
  24. //引數檢查
  25. if (nargs != 4) {  
  26.         ERROR("invalid line ueventd.rc line for '%s'\n", args[0]);  
  27. return;  
  28.     }  
  29. /* If path starts with [email protected] lookup the mount number. */
  30. if (!strncmp(name, "[email protected]", 4)) {  
  31. int n = mtd_name_to_number(name + 4);  
  32. if (n >= 0)  
  33.             asprintf(&tmp, "/dev/mtd/mtd%d", n);  
  34.         name = tmp;  
  35.     } else {  
  36. int len = strlen(name);  
  37. if (name[len - 1] == '*') {  
  38.             prefix = 1;  
  39.             name[len - 1] = '\0';  
  40.         }  
  41.     }  
  42. //許可權檢查
  43.     perm = strtol(args[1], &endptr, 8);  
  44. if (!endptr || *endptr != '\0') {  
  45.         ERROR("invalid mode '%s'\n", args[1]);  
  46.         free(tmp);  
  47. return;  
  48.     }  
  49. //從android_ids陣列中查詢uid
  50.     ret = get_android_id(args[2]);  
  51. if (ret < 0) {  
  52.         ERROR("invalid uid '%s'\n", args[2]);  
  53.         free(tmp);  
  54. return;  
  55.     }  
  56.     uid = ret;  
  57. //從android_ids陣列中查詢gid
  58.     ret = get_android_id(args[3]);  
  59. if (ret < 0) {  
  60.         ERROR("invalid gid '%s'\n", args[3]);  
  61.         free(tmp);  
  62. return;  
  63.     }  
  64.     gid = ret;  
  65. //為裝置檔案新增許可權
  66.     add_dev_perms(name, attr, perm, uid, gid, prefix);  
  67.     free(tmp);  
  68. }  
void set_device_permission(int nargs, char **args)
{
    char *name;
    char *attr = 0;
    mode_t perm;
    uid_t uid;
    gid_t gid;
    int prefix = 0;
    char *endptr;
    int ret;
    char *tmp = 0;

    if (nargs == 0)
        return;

    if (args[0][0] == '#')
        return;
/*  |name|  |permission| |user| |group|  */
    name = args[0];
    if (!strncmp(name,"/sys/", 5) && (nargs == 5)) {
        INFO("/sys/ rule %s %s\n",args[0],args[1]);
        attr = args[1];
        args++;
        nargs--;
    }
	//引數檢查
    if (nargs != 4) {
        ERROR("invalid line ueventd.rc line for '%s'\n", args[0]);
        return;
    }
    /* If path starts with [email protected] lookup the mount number. */
    if (!strncmp(name, "[email protected]", 4)) {
        int n = mtd_name_to_number(name + 4);
        if (n >= 0)
            asprintf(&tmp, "/dev/mtd/mtd%d", n);
        name = tmp;
    } else {
        int len = strlen(name);
        if (name[len - 1] == '*') {
            prefix = 1;
            name[len - 1] = '\0';
        }
    }
    //許可權檢查
    perm = strtol(args[1], &endptr, 8);
    if (!endptr || *endptr != '\0') {
        ERROR("invalid mode '%s'\n", args[1]);
        free(tmp);
        return;
    }
    //從android_ids陣列中查詢uid
    ret = get_android_id(args[2]);
    if (ret < 0) {
        ERROR("invalid uid '%s'\n", args[2]);
        free(tmp);
        return;
    }
    uid = ret;
    //從android_ids陣列中查詢gid
    ret = get_android_id(args[3]);
    if (ret < 0) {
        ERROR("invalid gid '%s'\n", args[3]);
        free(tmp);
        return;
    }
    gid = ret;
    //為裝置檔案新增許可權
    add_dev_perms(name, attr, perm, uid, gid, prefix);
    free(tmp);
}

首先檢查引數的合法性,並根據引數查詢uid、gid,對不同的使用者和組的uid、gid已經事先配置在陣列android_ids中了,如下:

[cpp] view plaincopyprint?
  1. staticconststruct android_id_info android_ids[] = {  
  2.     { "root",      AID_ROOT, },  
  3.     { "system",    AID_SYSTEM, },  
  4.     { "radio",     AID_RADIO, },  
  5.     { "bluetooth", AID_BLUETOOTH, },  
  6.     { "graphics",  AID_GRAPHICS, },  
  7.     { "input",     AID_INPUT, },  
  8.     { "audio",     AID_AUDIO, },  
  9.     { "camera",    AID_CAMERA, },  
  10.     { "log",       AID_LOG, },  
  11.     { "compass",   AID_COMPASS, },  
  12.     { "mount",     AID_MOUNT, },  
  13.     { "wifi",      AID_WIFI, },  
  14.     { "dhcp",      AID_DHCP, },  
  15.     { "adb",       AID_ADB, },  
  16.     { "install",   AID_INSTALL, },  
  17.     { "media",     AID_MEDIA, },  
  18.     { "drm",       AID_DRM, },  
  19.     { "mdnsr",     AID_MDNSR, },  
  20.     { "nfc",       AID_NFC, },  
  21.     { "drmrpc",    AID_DRMRPC, },  
  22.     { "shell",     AID_SHELL, },  
  23.     { "cache",     AID_CACHE, },  
  24.     { "diag",      AID_DIAG, },  
  25.     { "net_bt_admin", AID_NET_BT_ADMIN, },  
  26.     { "net_bt",    AID_NET_BT, },  
  27.     { "sdcard_r",  AID_SDCARD_R, },  
  28.     { "sdcard_rw", AID_SDCARD_RW, },  
  29.     { "media_rw",  AID_MEDIA_RW, },  
  30.     { "vpn",       AID_VPN, },  
  31.     { "keystore",  AID_KEYSTORE, },  
  32.     { "usb",       AID_USB, },  
  33.     { "mtp",       AID_MTP, },  
  34.     { "gps",       AID_GPS, },  
  35.     { "inet",      AID_INET, },  
  36.     { "net_raw",   AID_NET_RAW, },  
  37.     { "net_admin", AID_NET_ADMIN, },  
  38.     { "net_bw_stats", AID_NET_BW_STATS, },  
  39.     { "net_bw_acct", AID_NET_BW_ACCT, },  
  40.     { "misc",      AID_MISC, },  
  41.     { "nobody",    AID_NOBODY, },  
  42. };  
static const struct android_id_info android_ids[] = {
    { "root",      AID_ROOT, },
    { "system",    AID_SYSTEM, },
    { "radio",     AID_RADIO, },
    { "bluetooth", AID_BLUETOOTH, },
    { "graphics",  AID_GRAPHICS, },
    { "input",     AID_INPUT, },
    { "audio",     AID_AUDIO, },
    { "camera",    AID_CAMERA, },
    { "log",       AID_LOG, },
    { "compass",   AID_COMPASS, },
    { "mount",     AID_MOUNT, },
    { "wifi",      AID_WIFI, },
    { "dhcp",      AID_DHCP, },
    { "adb",       AID_ADB, },
    { "install",   AID_INSTALL, },
    { "media",     AID_MEDIA, },
    { "drm",       AID_DRM, },
    { "mdnsr",     AID_MDNSR, },
    { "nfc",       AID_NFC, },
    { "drmrpc",    AID_DRMRPC, },
    { "shell",     AID_SHELL, },
    { "cache",     AID_CACHE, },
    { "diag",      AID_DIAG, },
    { "net_bt_admin", AID_NET_BT_ADMIN, },
    { "net_bt",    AID_NET_BT, },
    { "sdcard_r",  AID_SDCARD_R, },
    { "sdcard_rw", AID_SDCARD_RW, },
    { "media_rw",  AID_MEDIA_RW, },
    { "vpn",       AID_VPN, },
    { "keystore",  AID_KEYSTORE, },
    { "usb",       AID_USB, },
    { "mtp",       AID_MTP, },
    { "gps",       AID_GPS, },
    { "inet",      AID_INET, },
    { "net_raw",   AID_NET_RAW, },
    { "net_admin", AID_NET_ADMIN, },
    { "net_bw_stats", AID_NET_BW_STATS, },
    { "net_bw_acct", AID_NET_BW_ACCT, },
    { "misc",      AID_MISC, },
    { "nobody",    AID_NOBODY, },
};

這些uid、gid都是以巨集的形式被定義:

[cpp] view plaincopyprint?
  1. #define AID_ROOT             0  /* traditional unix root user */
  2. #define AID_SYSTEM        1000  /* system server */
  3. #define AID_RADIO         1001  /* telephony subsystem, RIL */
  4. #define AID_BLUETOOTH     1002  /* bluetooth subsystem */
#define AID_ROOT             0  /* traditional unix root user */
#define AID_SYSTEM        1000  /* system server */
#define AID_RADIO         1001  /* telephony subsystem, RIL */
#define AID_BLUETOOTH     1002  /* bluetooth subsystem */

通過呼叫get_android_id函式在陣列android_ids中查詢對應的uid、gid

[cpp] view plaincopyprint?
  1. staticint get_android_id(constchar *id)  
  2. {  
  3.     unsigned int i;  
  4. for (i = 0; i < ARRAY_SIZE(android_ids); i++)  
  5. if (!strcmp(id, android_ids[i].name))  
  6. return android_ids[i].aid;  
  7. return 0;  
  8. }  
static int get_android_id(const char *id)
{
    unsigned int i;
    for (i = 0; i < ARRAY_SIZE(android_ids); i++)
        if (!strcmp(id, android_ids[i].name))
            return android_ids[i].aid;
    return 0;
}

函式實現比較簡單,通過遍歷陣列,並匹配陣列元素的name屬性來查詢指定name的uid或gid。

最後通過add_dev_perms函式來設定裝置檔案的操作許可權,該函式定義在system\core\init\devices.c檔案中,在該檔案中聲明瞭三個連結串列:

[cpp] view plaincopyprint?
  1. static list_declare(sys_perms);  
  2. static list_declare(dev_perms);  
  3. static list_declare(platform_names);  
static list_declare(sys_perms);
static list_declare(dev_perms);
static list_declare(platform_names);

add_dev_perms函式就是將解析得到的裝置及裝置屬性,新增到指定的連結串列中,

使用解析得到的內容來建立一個perm_node變數,並根據條件新增到sys_perms或dev_perms連結串列中。

[cpp] view plaincopyprint?
  1. int add_dev_perms(constchar *name, constchar *attr,  
  2.                   mode_t perm, unsigned int uid, unsigned int gid,  
  3.                   unsigned short prefix) {  
  4. //建立perm_node
  5. struct