Analysis of the vold daemon in Android

Source: Internet
Author: User

Address: http://www.chineselinuxuniversity.net/freesky/viewthread.php? Tid = 41

 

 

The full name of vold is volume daemon. In fact, it is responsible for completing the system's CDROM, USB large capacity storage, mmccard and other extended storage mounting tasks to automatically complete the daemon process. It supports hot swapping of these storage peripherals. Here is an introduction to GNU/Linux vold [http://vold.sourceforge.net/#. There is a big difference between the vold System on Android and the GNU/Linux system. Here we mainly analyze the processing process of the vold System on Android.

The vold processing process is roughly divided into three steps:
1. Create a link:
As a daemon, vold receives the driver information and sends the information to the application layer. On the other hand, it accepts and completes the upper-layer commands. Therefore, there are two links:
(1) vold socket: responsible for transferring information between vold and the application layer;
(2) socket accessing udev: responsible for transmitting vold and underlying information;
Both links are created at the beginning of the process.

2. Guidance:
Here, the processing of existing peripheral storage devices is mainly performed when the vold is started. First, load and parse vold. conf,
And check whether the mount point has been mounted (note: the purpose of checking the mount point here is not very clear !); Next, mount the mmccard and process the large-capacity USB storage.

3. event handling:
Here, two links are monitored to process dynamic events and respond to upper-layer application operations.

Let's analyze the code process in detail. Let's take a look at the startup and handling process of vold with an mmccard as an example. We start with the implementation of the vold main function:

First, create two sockets. First, the link between vold and the upper-layer application is created.
// Socket to listen on for incomming framework connections
If (door_sock = android_get_control_socket (vold_socket) <0 ){
LogE ("obtaining file descriptor socket '% s' failed: % s ",
Vold_socket, strerror (errno ));
Exit (1 );
}
Door_sock is the file descriptor of the vold_socket listener. Vold_socket is the socket device file created when the vold service is started in init. RC. The upper-layer application layer-mountlistener, which connects to the vold socket-as the client, and then interacts with the vold through the connection. When a client connects to this vold socket, the vold that listens to door_sock generates its own socket descriptor fw_sock, and transmits and accepts the upper layer information through it.
Create a socket for the interaction between the vold and the underlying information.

If (uevent_sock = socket (pf_netlink,
Sock_dgram, netlink_kobject_uevent) <0 ){
LogE ("unable to create uevent socket: % s", strerror (errno ));
Exit (1 );
}

Here, we use the netlink_kobject_uevent socket to access and obtain udev information. About udev, This is a Linux kernel device management module. For more information, see online. Here we only need to know that the device's hot swapping information is obtained from this module.

The following describes the boot wizard process. First, execute volmgr_bootstrap () to parse the vold. conf file. This file mainly contains the following information. We use the default vold. conf in the simulator as an example.
Volume_sdcard {
# This is the direct uevent device path to the SD slot on the device
Emu_media_path/devices/platform/goldfish_mmc.0/mmc_host/mmc0

Media_type MMC
Mount_point/sdcard
Ums_path/devices/platform/usb_mass_storage/lun0
}

Save the parsed information in a global structure variable and read the/proc/mounts information to check whether the mount point has been mounted. There is only one mmccard slot, so only one mount point is defined.

Next is the mmc_bootstrap () function. There are a series of calls and processing, mainly for directories. The call relationship is as follows,
Mmc_bootstrap () → mmc_bootstrap_controller () → mmc_bootstrap_card ()
After these steps, we have entered the/sys/devices/platform/goldfish_mmc.0/mmc_host/mmc0/mmc0: e118 folder in the mmc_bootstrap_card () call. Here is where the mmccard in our current slot stores device information, and then obtains relevant information, which prepares for the subsequent uevent generation. Let's briefly talk about the uevent event processing system. The following is the global variable dispatch_table in the code.

Static struct uevent_dispatch dispatch_table [] = {
{"Switch", handle_switch_event },
{"Battery", handle_battery_event },
{"MMC", handle_mmc_event },
{"Block", handle_block_event },
{"BDI", handle_bdi_event },
{"Power_Supply", handle_powersupply_event },
{Null, null}
};

This mainly stores different processing methods for uevent of different devices. Use the dispatch_event () function to obtain the name of the event, locate the event, and perform the corresponding operation. The dispatch_table global variable stores the correspondence between all events and the processing handle. In dispatch_event (), the global table is traversed to complete the corresponding call. Dispatch_event () requires a struct uevent *, that is, the uevent pointer as the parameter. Here, uevent is the structure of the event, which is defined as follows.

Struct uevent {
Char * path;
Enum uevent_action action;
Char * subsystem;
Char * Param [uevent_params_max];
Unsigned int seqnum;
};

There are two main methods to call dispatch_event () in vold. One is to capture the underlying message of udev and then execute process_uevent_message () to execute dispatch_event (); the other is to call the simulate_uevent () function during the boot duration, open up the memory, generate a uevent through parameters, and then execute dispatch_event (). During the guidance of our mmccard, we need to call the simulate_uevent () function several times. In this function, a uevent instance is generated and initialized Based on the parameter, and then the instance is passed as the parameter to the dispatch_event () function to complete the event execution process. Next we will go back to the mmccard boot process. Let's take a look at this process.
The work of the simulate_uevent () function.

Let's take a look at the configuration in the Virtual Machine file directory.
# Pwd
/Sys/devices/platform/goldfish_mmc.0/mmc_host/mmc0/mmc0: e118
# Ls-l
-RW-r -- root Root 4096 uevent
-R -- root Root 4096 CID
-R -- root Root 4096 CSD
-R -- root Root 4096 SCR
-R -- root Root 4096 date
-R -- root Root 4096 fwrev
-R -- root Root 4096 hwrev
-R -- root Root 4096 manfid
-R -- root Root 4096 name
-R -- root Root 4096 oemid
-R -- root Root 4096 serial
-R -- root Root 4096 type
Lrwxrwxrwx Root subsystem->.../../bus/MMC
Drwxr-XR-x Root power
Lrwxrwxrwx Root driver->.../../bus/MMC/Drivers/mmcblk
Drwxr-XR-x Root Block

Various Types and names of mmccards stored in the files. Let's look at the code of the mmc_bootstrap_card () function:
// File: MMC. c
Static int mmc_bootstrap_card (char * sysfs_path)
{
... ...
Sprintf (TMP, "devpath = % s", devpath );
Uevent_params [0] = (char *) strdup (TMP );

Sprintf (filename, "/sys % S/type", devpath );
P = read_file (filename, & sz );
P [strlen (P)-1] = '\ 0 ';
Sprintf (TMP, "mmc_type = % s", P );
Free (P );
Uevent_params [1] = (char *) strdup (TMP );

Sprintf (filename, "/sys % S/Name", devpath );
P = read_file (filename, & sz );
P [strlen (P)-1] = '\ 0 ';
Sprintf (TMP, "mmc_name = % s", P );
Free (P );
Uevent_params [2] = (char *) strdup (TMP );

Uevent_params [3] = (char *) NULL;

If (simulate_uevent ("MMC", devpath, "add", uevent_params) <0 ){
LogE ("error simulating uevent (% m )");
Return-errno;
}
... ...
}

Pass in the uevent struct using the simulate_uevent () parameter. Here, the loading information of an mmccard is executed. We can see that the path, type, name, and other information of the mmccard is stored in char * uevent_params [4.
And pass it into simulate_uevent (). Let's go to the simulate_uevent () function.

Int simulate_uevent (char * subsys, char * path, char * Action, char ** Params)
{
Struct uevent * event;
Char TMP [255];
Int I, RC;

If (! (Event = malloc (sizeof (struct uevent )))){
LogE ("error allocating memory (% s)", strerror (errno ));
Return-errno;
}

Memset (event, 0, sizeof (struct uevent ));

Event-> subsystem = strdup (subsys );

If (! Strcmp (action, "add "))
Event-> action = action_add;
Else if (! Strcmp (action, "change "))
Event-> action = action_change;
Else if (! Strcmp (action, "Remove "))
Event-> action = action_remove;
Else {
LogE ("invalid action '% S'", action );
Return-1;
}

Event-> Path = strdup (PATH );

For (I = 0; I <uevent_params_max; I ++ ){
If (! Params)
Break;
Event-> param = strdup (Params );
}

Rc = dispatch_uevent (event );
Free_uevent (event );
Return RC;
}

We can see that the simulate_uevent () function is generated and initialized according to the parameter. Finally, we call dispatch_uevent () to execute this simulated event.

The processing function dispatch_uevent () is called Based on the name. handle_mmc_event () is called here for processing. In fact, this process does not load the mmccard to the/sdcard mount point. The mounting process is still below. :-) Continue the analysis.

After processing, the mmc_bootstrap_card () process continues,
Mmc_bootstrap_card () → mmc_bootstrap_block () → mmc_bootstrap_mmcblk () → mmc_bootstrap_mmcblk_partition ()
This is the execution process. The mmc_bootstrap_mmcblk_partition () function is executed twice in total. The main difference between the two is the parameter difference. The first call parameter is:
/Sys/devices/platform/goldfish_mmc.0/mmc_host/mmc0/mmc0: e118/block/mmcblk0
Execute simulate_uevent () to add block information. The parameters for the second call are:
/Sys/devices/platform/goldfish_mmc.0/mmc_host/mmc0/mmc0: e118/block/mmcblk0/mmcblk0p1
Let's take a look at the implementation of this function:
Static int mmc_bootstrap_mmcblk (char * devpath)
{
... ...
If (rc = mmc_bootstrap_mmcblk_partition (devpath ))){
... ...
}
... ...
For (part_no = 0; part_no <4; part_no ++ ){
... ...
If (mmc_bootstrap_mmcblk_partition (part_devpath ))
... ...
}
}
... ...
}
We have provided the path parameters for the two calls. The first call of the mmc_bootstrap_mmcblk_partition () function adds the disk information of the mmccard, and creates a block device to record the information. The main information is the partition information of the disk, this will play a decisive role in subsequent mounting. Mounting is actually only performed on the partition. Mmc_bootstrap_mmcblk_partition () simulates the event by calling the simulate_uevent () function, and finally completes the operation. It is worth noting that mounting is performed asynchronously through a separate thread. Here, we will introduce the analysis at startup. The specific code calling is complicated. You can trace the code to analyze the specific implementation.

Since the mounting of USB large-capacity storage has not yet been implemented, ums_bootstrap () is an empty function, so this part can be skipped. There is also switch_bootstrap (), which seems to be something for processing USB storage. The specific code has not been carefully read yet. I will continue to update it later.

In this way, we will return to the vold main function again. Next, the while loop is blocked. We need to listen to the two link descriptors and execute their respective requests. Here we use the familiar select system call. When a request with a link to vold socket comes in, the link descriptor fw_sock between the application layer and vold gets the value.

============
Run the following command to start the vold daemon thread and create a socket in init. RC:
Service vold/system/bin/vold
Socket vold stream 0660 root Mount

======================
One thing to note is that when mountd was used in the past, the same principle was used and a socket was created.
Now these have been commented out in init. RC.
# Service mountd/system/bin/mountd
# Socket mountd stream 0660 root Mount

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.