android 中的ueventd是一个守护进程,主要作用是接收uevent来创建或删除/dev/xxx(设备节点),ueventd代码不多,下面我们直接针对代码分析。
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 willlook
* for androidboot.hardware param in kernel cmdline, and save its valuein
* hardware[]. */
import_kernel_cmdline(0, import_kernel_nv);
get_hardware_name(hardware, &revision);
//解析ueventd.rc和ueventd.xx.rc,将文件中的每一行信息存放到一个perm_node结构体,然后将这些结构体组成一个双向链表,每一行包含文件名、uid、gid、权限等
ueventd_parse_config_file("/ueventd.rc");
snprintf(tmp, sizeof(tmp), "/ueventd.%s.rc", hardware);
ueventd_parse_config_file(tmp);
//1.建立接收uevent的socket 2.如果没有做过coldboot,做一次coldboot
//所谓coldboot是指让kernel重新生成deviceadd事件
device_init();
ufd.events = POLLIN;
ufd.fd = get_device_fd();
//循环poll ufd的POLLIN事件, POLLIN事件表示有数据可读,具体可参考linux poll系统调用的相关资料
while(1) {
ufd.revents = 0;
nr = poll(&ufd, 1, -1);
if (nr <= 0)
continue;
if (ufd.revents == POLLIN)
handle_device_fd(); //详见下文
}
}
#define UEVENT_MSG_LEN 1024
void handle_device_fd()
{
char msg[UEVENT_MSG_LEN+2];
int n;
while ((n = uevent_kernel_multicast_recv(device_fd, msg,UEVENT_MSG_LEN)) > 0) {
if(n >= UEVENT_MSG_LEN) /*overflow -- discard */
continue;
msg[n] = '\0';
msg[n+1] = '\0';
struct uevent uevent;
//解析uevent消息,保存到uevent变量中
parse_event(msg, &uevent);
handle_device_event(&uevent); //详见下文
//处理subsystem是firmware的uevent,详见下文
handle_firmware_event(&uevent);
}
}
static void handle_device_event(structuevent *uevent)
{
//针对action为add和changer,修复一下文件权限
if (!strcmp(uevent->action,"add") ||!strcmp(uevent->action, "change"))
fixup_sys_perms(uevent->path);
//针对block、platform等设备进行处理
if (!strncmp(uevent->subsystem, "block", 5)) {
handle_block_device_event(uevent);
}else if (!strncmp(uevent->subsystem, "platform", 8)) {
handle_platform_device_event(uevent);
}else {
handle_generic_device_event(uevent);
}
}