ueventd主要是负责设备节点的创建、权限设定等一些列工作。服务通过使用uevent,监控驱动发送的消息,做进一步处理。
ueventd实际和init是同一个binary,只是走了不同分支,可参看前一部分。ueventd的整体代码比较简单,主要是三部分:
- 解析ueventd.rc
- 初始化设备信息
- 循环polling uevent消息
主函数及相关功能如下如下:
1.ueventd.ueventd_main
代码路径:/system/core/init/ueventd.cpp
(http://androidxref.com/8.0.0_r4/xref/system/core/init/ueventd.cpp)
39int ueventd_main(int argc, char **argv) 40{ 41 /* 42 * init sets the umask to 077 for forked processes. We need to 43 * create files with exact permissions, without modification by 44 * the umask. 45 */ 46 umask(000); 47 48 /* Prevent fire-and-forget children from becoming zombies. 49 * If we should need to wait() for some children in the future 50 * (as opposed to none right now), double-forking here instead 51 * of ignoring SIGCHLD may be the better solution. 52 */ 53 signal(SIGCHLD, SIG_IGN); 54 55 InitKernelLogging(argv); 56 57 LOG(INFO) << "ueventd started!"; 58 59 selinux_callback cb; 60 cb.func_log = selinux_klog_callback; 61 selinux_set_callback(SELINUX_CB_LOG, cb); 62 63 ueventd_parse_config_file("/ueventd.rc"); 64 ueventd_parse_config_file("/vendor/ueventd.rc"); 65 ueventd_parse_config_file("/odm/ueventd.rc"); 66 67 /* 68 * keep the current product name base configuration so 69 * we remain backwards compatible and allow it to override 70 * everything 71 * TODO: cleanup platform ueventd.rc to remove vendor specific 72 * device node entries (b/34968103) 73 */ 74 std::string hardware = android::base::GetProperty("ro.hardware", ""); 75 ueventd_parse_config_file(android::base::StringPrintf("/ueventd.%s.rc", hardware.c_str()).c_str()); 76 77 device_init(); 78 79 pollfd ufd; 80 ufd.events = POLLIN; 81 ufd.fd = get_device_fd(); 82 83 while (true) { 84 ufd.revents = 0; 85 int nr = poll(&ufd, 1, -1); 86 if (nr <= 0) { 87 continue; 88 } 89 if (ufd.revents & POLLIN) { 90 handle_device_fd(); 91 } 92 } 93 94 return 0; 95}
2.处理和解析ueventd.rc
代码路径:/system/core/rootdir/ueventd.rc
(http://androidxref.com/8.0.0_r4/xref/system/core/rootdir/ueventd.rc)
这部分相比init.rc来说,巨简单,没什么特别的。主要是通过rc文件,来控制目录节点的权限。如:
11/dev/null 0666 root root 12/dev/zero 0666 root root 13/dev/full 0666 root root 14/dev/ptmx 0666 root root 15/dev/tty 0666 root root 16/dev/random 0666 root root 17/dev/urandom 0666 root root 18# Make HW RNG readable by group system to let EntropyMixer read it. 19/dev/hw_random 0440 root system 20/dev/ashmem 0666 root root 21/dev/binder 0666 root root 22/dev/hwbinder 0666 root root 23/dev/vndbinder 0666 root root
详情应该不需要展开,基本都能了解。
3.devices.device_init
代码路径:/system/core/init/devices.cpp
(http://androidxref.com/8.0.0_r4/xref/system/core/init/devices.cpp)
设备初始化
kernel在加载设备时,会通过socket发送uevent事件给userspace, 在init里,通过接受这些uevent事件,来创建设备的节点。主要函数是device_init()初始化函数为device_init,如下
1036void device_init(const char* path, coldboot_callback fn) { 1037 if (!sehandle) { 1038 sehandle = selinux_android_file_context_handle(); 1039 } 1040 // open uevent socket and selinux status only if it hasn't been 1041 // done before 1042 if (device_fd == -1) { 1043 /* is 256K enough? udev uses 16MB! */ 1044 device_fd.reset(uevent_open_socket(256 * 1024, true)); 1045 if (device_fd == -1) { 1046 return; 1047 } 1048 fcntl(device_fd, F_SETFL, O_NONBLOCK); 1049 selinux_status_open(true); 1050 } 1051 1052 if (access(COLDBOOT_DONE, F_OK) == 0) { 1053 LOG(VERBOSE) << "Skipping coldboot, already done!"; 1054 return; 1055 } 1056 1057 Timer t; 1058 coldboot_action_t act; 1059 if (!path) { 1060 act = coldboot("/sys/class", fn); 1061 if (!should_stop_coldboot(act)) { 1062 act = coldboot("/sys/block", fn); 1063 if (!should_stop_coldboot(act)) { 1064 act = coldboot("/sys/devices", fn); 1065 } 1066 } 1067 } else { 1068 act = coldboot(path, fn); 1069 } 1070 1071 // If we have a callback, then do as it says. If no, then the default is 1072 // to always create COLDBOOT_DONE file. 1073 if (!fn || (act == COLDBOOT_FINISH)) { 1074 close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000)); 1075 } 1076 1077 LOG(INFO) << "Coldboot took " << t; 1078}
4.uevent.open_uevent_socket
代码路径:/system/core/libcutils/uevent.c
(http://androidxref.com/8.0.0_r4/xref/system/core/libcutils/uevent.c)
open_uevent_socket();
这是打开uevent的socket。这里的uevent是用到netlink中的内核事件向用户态通知(NETLINK_KOBJECT_UEVENT)功能,是内核和用户态进行双向数据传输的非常好的方式,除了eventd外,netd和vold也是使用uevent的。初始化函数中,比较要注意的coldboot这个函数,字面意思是冷启动,它的作用是,对那些在uventd启动前,已经add上的驱动,再重新操作一下,让他们再发一次event消息,上层号针对性处理。
这里对 /sys/class,/sys/block和/sys/devices下的设备遍历一遍:
104int uevent_open_socket(int buf_sz, bool passcred) 105{ 106 struct sockaddr_nl addr; 107 int on = passcred; 108 int s; 109 110 memset(&addr, 0, sizeof(addr)); 111 addr.nl_family = AF_NETLINK; 112 addr.nl_pid = getpid(); 113 addr.nl_groups = 0xffffffff; 114 115 s = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT); 116 if(s < 0) 117 return -1; 118 119 /* buf_sz should be less than net.core.rmem_max for this to succeed */ 120 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz, sizeof(buf_sz)) < 0) { 121 close(s); 122 return -1; 123 } 124 125 setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); 126 127 if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 128 close(s); 129 return -1; 130 } 131 132 return s; 133}write(fd, "add\n", 4)激活内核,重发add事件的uevent,handle_device_fd();针对event消息,做响应的处理。
5.devices.handle_device_fd
代码路径:/system/core/init/devices.cpp
(http://androidxref.com/8.0.0_r4/xref/system/core/init/devices.cpp)
uevent消息处理
初始化好了之后,daemon程序只要polling新的event事件即可,polling到了,就调用handle_device_fd();来处理,可以看看这个函数:
947coldboot_action_t handle_device_fd(coldboot_callback fn) 948{ 949 coldboot_action_t ret = handle_device_fd_with( 950 [&](uevent* uevent) -> coldboot_action_t { 951 if (selinux_status_updated() > 0) { 952 struct selabel_handle *sehandle2; 953 sehandle2 = selinux_android_file_context_handle(); 954 if (sehandle2) { 955 selabel_close(sehandle); 956 sehandle = sehandle2; 957 } 958 } 959 960 // default is to always create the devices 961 coldboot_action_t act = COLDBOOT_CREATE; 962 if (fn) { 963 act = fn(uevent); 964 } 965 966 if (act == COLDBOOT_CREATE || act == COLDBOOT_STOP) { 967 handle_device_event(uevent); 968 handle_firmware_event(uevent); 969 } 970 971 return act; 972 }); 973 974 return ret; 975}handle_device_event功能就是接受内核发的event消息,然后parser此消息,处理对应的消息事件。
820static void handle_device_event(struct uevent *uevent) 821{ 822 if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online")) 823 fixup_sys_perms(uevent->path, uevent->subsystem); 824 825 if (!strncmp(uevent->subsystem, "block", 5)) { 826 handle_block_device_event(uevent); 827 } else if (!strncmp(uevent->subsystem, "platform", 8)) { 828 handle_platform_device_event(uevent); 829 } else { 830 handle_generic_device_event(uevent); 831 } 832}
handle_firmware_event主要功能,就是根据发过来的uevent,创建/删除设备节点,同时以ueventd.rc中描述的权限设置更新一些节点权限。
901static void handle_firmware_event(uevent* uevent) { 902 if (strcmp(uevent->subsystem, "firmware")) return; 903 if (strcmp(uevent->action, "add")) return; 904 905 // Loading the firmware in a child means we can do that in parallel... 906 // (We ignore SIGCHLD rather than wait for our children.) 907 pid_t pid = fork(); 908 if (pid == 0) { 909 Timer t; 910 process_firmware_event(uevent); 911 LOG(INFO) << "loading " << uevent->path << " took " << t; 912 _exit(EXIT_SUCCESS); 913 } else if (pid == -1) { 914 PLOG(ERROR) << "could not fork to process firmware event for " << uevent->firmware; 915 } 916}如果有协处理器, 还要下载协处理器的firmware,这里是处理协处理器要下载firmware的指令,fork一个子进程处理。