Android uevent程序原始碼分析
在Android Init程序原始碼分析中講到init程序會依次執行被加入到待執行佇列action_queue中的Action,在init.rc中我們有這麼一段配置:
[plain] view plaincopyprint?- 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
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- 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?
- KEYWORD(start, COMMAND, 1, do_start)
在解析命令列時,被新增到Action的commands連結串列中: [cpp] view plaincopyprint?KEYWORD(start, COMMAND, 1, do_start)
- 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);
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?- 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)
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?- 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);
- .....
- }
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?- 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();
- }
- }
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?
- /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
/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?- int ueventd_parse_config_file(constchar *fn)
- {
- char *data;
- //讀取檔案內容
- data = read_file(fn, 0);
- if (!data) return -1;
- //解析整個rc檔案內容
- parse_config(fn, data);
- DUMP();
- return 0;
- }
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?- staticvoid parse_config(constchar *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;
- }
- }
- }
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?- staticvoid parse_line_device(struct parse_state* state, int nargs, char **args)
- {
- set_device_permission(nargs, args);
- }
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
- 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);
- }
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?- staticconststruct 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, },
- };
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?- #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 */
#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?- staticint get_android_id(constchar *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;
- }
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?- static list_declare(sys_perms);
- static list_declare(dev_perms);
- 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?- int add_dev_perms(constchar *name, constchar *attr,
- mode_t perm, unsigned int uid, unsigned int gid,
- unsigned short prefix) {
- //建立perm_node
- struct