Transferred from: http://blog.csdn.net/freshui/article/details/2132299
(Lazy people recently think of me and csdn for a long time, this Android init is lying in my draft box for almost 5 years, a little change to send it out)
UEVENTD is mainly responsible for the creation of device nodes, permission settings and other tasks. The service uses Uevent to monitor the messages sent by the driver for further processing.
Ueventd Actual and Init are the same binary, just walk the different branches and see the previous section.
Ueventd's overall code is relatively simple, mainly three parts:
- Parsing ueventd.rc
- Initializing device information
- Looping polling uevent messages
The main functions and related functions are as follows:
[CPP]View PlainCopy
- int Ueventd_main (int argc, char **argv)
- {
- //As with INIT, no std input and output
- Open_devnull_stdio ();
- //Initialize kernel log, let Ueventd log output to the string via kernel PRINTK log
- Klog_init ();
- //parsing and processing of UEVENTD RC files
- Import_kernel_cmdline (0, Import_kernel_nv);
- Get_hardware_name (Hardware, &revision);
- Ueventd_parse_config_file ("/ueventd.rc");
- SNPRINTF (TMP, sizeof (TMP), "/ueventd.%s.rc", hardware);
- Ueventd_parse_config_file (TMP);
- //Device initialization
- Device_init ();
- //Polling uevent messages to manage the device
- Ufd.events = Pollin;
- UFD.FD = GET_DEVICE_FD ();
- While (1) {
- ufd.revents = 0;
- NR = Poll (&UFD, 1,-1);
- if (nr <= 0)
- continue;
- if (ufd.revents = = Pollin)
- HANDLE_DEVICE_FD (); //Polling to message, handling event message
- }
- }
Processing and parsing ueventd.rc
This part compared to init.rc, giant simple, nothing special. Mainly through the RC file, to control the permissions of the directory node. Such as:
[Plain]View PlainCopy
- /DEV/TTYUSB2 0666 Radio Radio
- /dev/ts0710mux* 0640 Radio Radio
- /DEV/PPP 0666 Radio VPN
- # SYSFS Properties
- /sys/devices/virtual/input/input* Enable 0666 System system
- /sys/devices/virtual/input/input* Poll_delay 0666 System System
Details should not need to be expanded, basically can understand.
Device initialization
Kernel when the device is loaded, the Uevent event is sent through the socket to userspace, in Init, to create the node of the device by accepting these uevent events. The main function is Device_init ()
The initialization function is Device_init, as follows
[CPP]View PlainCopy
- void Device_init (void)
- {
- suseconds_t t0, T1;
- struct STAT info;
- int fd;
- Sehandle = NULL;
- if (is_selinux_enabled () > 0) {
- Sehandle = Selinux_android_file_context_handle ();
- }
- / * is 256K enough udev uses 16mb! * /
- DEVICE_FD = Uevent_open_socket (256*1024, true);
- if (device_fd < 0)
- return;
- Fcntl (DEVICE_FD, F_SETFD, fd_cloexec);
- Fcntl (DEVICE_FD, F_SETFL, O_nonblock);
- if (stat (Coldboot_done, &info) < 0) {
- T0 = Get_usecs ();
- Coldboot ("/sys/class");
- Coldboot ("/sys/block");
- Coldboot ("/sys/devices");
- T1 = Get_usecs ();
- FD = open (Coldboot_done, o_wronly| o_creat, 0000);
- Close (FD);
- Log_event_print ("Coldboot%ld us\n", ((long) (t1-t0)));
- } Else {
- Log_event_print ("Skipping coldboot, already done\n");
- }
- }
Open_uevent_socket ();
This is the socket that opens the uevent. The uevent here is used to netlink the kernel event to the User state notification (netlink_kobject_uevent) function, is the kernel and the user configuration for two-way data transmission of the very good way, in addition to eventd outside, NETD and Vold are also used in uevent.
In the initialization function, the comparison to pay attention to the Coldboot this function, the literal meaning is cold start, it is the role of those in the Uventd before the start, already add on the driver, and then re-operation, let them send an event message, the upper number targeted processing.
Here, the devices under/sys/class,/sys/block and/sys/devices are traversed again:
[CPP]View PlainCopy
- static void Do_coldboot (DIR *d)
- {
- struct dirent *de;
- int DFD, FD;
- DFD = DIRFD (d);
- FD = Openat (DFD, "Uevent", o_wronly);
- if (fd >= 0) {
- Write (FD, "add\n", 4);
- Close (FD);
- HANDLE_DEVICE_FD ();
- }
- While ((de = Readdir (d))) {
- DIR *d2;
- if (de->d_type! = Dt_dir | | de->d_name[0] = = '. ')
- continue;
- FD = Openat (DFD, de->d_name, O_rdonly | O_directory);
- if (FD < 0)
- continue;
- D2 = Fdopendir (FD);
- if (D2 = = 0)
- Close (FD);
- else {
- Do_coldboot (D2);
- Closedir (D2);
- }
- }
- }
Write (FD, "add\n", 4) activates the kernel, re-sends the UEVENT,HANDLE_DEVICE_FD () of the Add event, and responds to the event message.
Uevent Message Processing
After the initialization is good, daemon program as long as polling new event events, polling to, call HANDLE_DEVICE_FD (), to handle, you can look at this function:
[CPP]View PlainCopy
- 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] = ' + ';
- MSG[N+1] = ' + ';
- struct uevent uevent;
- Parse_event (msg, &uevent);
- Handle_device_event (&uevent);
- Handle_firmware_event (&uevent);
- }
- }
The function is to accept the inside of the event message, and then parser this message to process the corresponding message event.
Over here:
[CPP]View PlainCopy
- static void handle_device_event (struct uevent *uevent)
- {
- if (!strcmp (Uevent->action,"add") | |!strcmp (uevent->action, "Change"))
- Fixup_sys_perms (Uevent->path);
- 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);
- }
- }
The main function is to create/delete device nodes based on the uevent sent, and update some node permissions with the permission settings described in Ueventd.rc.
[CPP]View PlainCopy
- static void handle_firmware_event (struct uevent *uevent)
- {
- pid_t pid;
- int ret;
- if (strcmp (Uevent->subsystem, "firmware"))
- return;
- if (strcmp (Uevent->action, "Add"))
- return;
- / * We fork, to avoid making large memory allocations in init proper * /
- PID = fork ();
- if (!pid) {
- Process_firmware_event (uevent);
- Exit (exit_success);
- }
- }
If there is a coprocessor, but also to download the coprocessor firmware, here is the processing coprocessor to download firmware instructions, fork a child process processing.
Android Init Process Analysis Ueventd