Author: gzshun. Original Works. Reprinted, please indicate the source!
Vold is the core part of the Android system processing disk. It replaces the udev in the original Linux system and is mainly used to process hot swapping storage devices in the Android system. In systems later than android2.2, the vold source code has been moved to the system directory, and the vold directory contains the following source code:
── Android. mk
── ASEC. h
├ ── Cleanspec. mk
── Commandlistener. cpp
── Commandlistener. h
── Devmapper. cpp
── Devmapper. h
├ ── Directvolume. cpp
├ ── Directvolume. h
── Fat. cpp
── Fat. h
── Hash. h
── Logwrapper. c
── Loop. cpp
── Loop. h
── Main. cpp
── Netlinkhandler. cpp
── Netlinkhandler. h
── Netlinkmanager. cpp
── Netlinkmanager. h
── Process. cpp
── Process. h
── Responsecode. cpp
── Responsecode. h
── VDC. c
── Voldcommand. cpp
── Voldcommand. h
── Volume. cpp
── Volume. h
── Volumemanager. cpp
── Volumemanager. h
── Xwarp. cpp
── Xwarp. h
First, briefly describe the inheritance relationship of classes. vold has the following important classes:
Three major management classes: volumemanager, commandlistener, and netlinkmanager
Other processing classes: volume, directvolume, netlinkhandler, fat, responsecode
Other related classes: netlinklistener and socketlistener
1. volumemanager manages the volume class;
2. The directvolume class inherits from the volume class and stores disk information and operation functions;
3. The netlinkmanager class is responsible for communicating with the kernel uevent events. During this period, netlinklistener and socketlistener class functions are used;
4. Fat is a function used to format the SD card;
5. responsecode stores the value provided by vold to the framework.
This article describes the source code of the Main. cpp file:
Int main () {/************************************** **************************************** * ***** the following three classes declare three pointer objects: ** volumemanager: manages all storage devices (volume objects). ** commandlistener: listens to messages sent by the framework, analyzes commands, and calls the response operation function. ** netlinkmanager: monitors hot swapping events in the Linux kernel, uevent event ************************************** **************************************** * ***/volumemanager * VM; commandlistener * Cl; netlinkmanager * NM; slogi ("vold 2.1 (the r Evenge) Firing up "); /*************************************** **************************************** * ***** in Linux, for example, for a SCSI hard disk, the device node of the USB flash disk is generated under the/dev/directory by default. Android changes the ** nodes of these devices to the/dev/block/directory. However, with the emergence of hot swapping events, device nodes (such as SDA and SDB) often change. ** it may be a little troublesome for vold, therefore, a directory named vold is created under/dev/block/to store the SDA and ** device nodes corresponding to SDB, as shown in ". ** Eg: The primary and secondary device numbers of SDA are 8, 0, respectively, so vold creates a node named "8:0" in the vold directory, named based on the primary and secondary device numbers, it facilitates program operations and increases flexibility. **************************************** **************************************** **/Mkdir ("/dev/block/vold ", 0755 ); /*************************************** **************************************** * *** instantiate a VM object, the volumemanager class calls its own instance function and adds an object to the VM. ** Source code: volumemanager * volumemanager: instance () {If (! Sinstance) sinstance = new volumemanager (); Return sinstance ;} **************************************** **************************************** **/If (! (Vm = volumemanager: instance () {sloge ("unable to create volumemanager"); exit (1 );}; /*************************************** **************************************** * *** instantiate an NM object, the netlinkmanager class calls its own instance function and adds an object to nm. ** Source code: netlinkmanager * netlinkmanager: instance () {If (! Sinstance) sinstance = new netlinkmanager (); Return sinstance ;} **************************************** **************************************** **/If (! (Nm = netlinkmanager: instance () {sloge ("unable to create netlinkmanager"); exit (1 );}; /*************************************** **************************************** * *** instantiate the CL object; ** VM-> setbroadcaster (socketlistener *) Cl); ** the setbroadcaster function sets the member variable mbroadcaster of volumemanager to Cl, both of which are the pointer type of ** socketlistener, the Command Execution status Broadcast Function calls the socketlistener pointer to call the Broadcast Function of the ** socketlistener class. ** why can the socketlistener class be forcibly converted to commandlis? What about the tener class? ** Cause: inheritance relationship: commandlistener (subclass) --> frameworklistener (subclass) --> socketlistener (parent class) ** it is correct to forcibly convert the subclass to the parent class. **************************************** **************************************** **/Cl = new commandlistener (); VM-> setbroadcaster (socketlistener *) Cl); nm-> setbroadcaster (socketlistener *) Cl ); /*************************************** **************************************** * *** call the start function to start the management class of the storage device, after reading the source code, this function does not do anything. it is estimated where soy sauce is going. ** Source code: int volumemanager: Start () {return 0 ;} **************************************** **************************************** **/If (Vm-> Start ()) {sloge ("unable to start volumemanager (% s)", strerror (errno); exit (1 );} /*************************************** **************************************** * *** the process_config function is used to parse/etc/vold. the fstab configuration file can be seen from the code that the parameter ** of the configuration file is separated by a space and a table (Tab key). The system starts up and analyzes the configuration file, mount the corresponding partition, equivalent ** Linux/etc/fstab file. **************************************** **************************************** **/If (process_config (VM )) {sloge ("error reading configuration (% s )... continuing anyways ", strerror (errno ));} /*************************************** **************************************** * the NM object calls the start function to open a thread, it is used to listen to the underlying uevent events. This start function does more **. It mainly opens a UDP socket and listens to the underlying events cyclically. The select function is used in the thread to process the ** socket, which is designed for the use of fd_set struct and so on. ** when a uevent event is captured, vold notifies the framework layer of the event, framework, and then ** issue the Operation Command. **************************************** **************************************** **/If (nm-> Start ()) {sloge ("unable to start netlinkmanager (% s)", strerror (errno); exit (1) ;}coldboot ("/sys/block "); /*************************************** **************************************** * ***** The following describes whether the Android system is in ums state, ums refers to large-capacity storage, which is the OTG function of the Android system. OTG is short for on-the-go and mainly provides connection with the PC. ** the policyumsconnected function notifies the UMS status to the framework layer, so the framework works with the UI, A ** interaction interface with the PC is displayed. **************************************** **************************************** **/{File * FP; char State [255]; If (FP = fopen ("/sys/devices/virtual/switch/usb_mass_storage/State", "R "))) {If (fgets (State, sizeof (state), FP) {If (! Strncmp (state, "online", 6) {VM-> policyumsconnected (true);} else {VM-> policyumsconnected (false );}} else {sloge ("failed to read switch state (% s)", strerror (errno) ;}fclose (FP );} else {slogw ("No ums switch available ");}} /*************************************** **************************************** * ***** the above preparations have been completed, it is now an important processing thread of vold. ** startlistener is a function of the parent class of the commandlistener class. It is used to enable the listening thread and listen to the function at the ** framework layer. The command sent to vold, and then the corresponding command is called to operate the storage device. **************************************** **************************************** **/If (Cl-> startlistener ()) {sloge ("unable to start commandlistener (% s)", strerror (errno); exit (1 );} /*************************************** **************************************** * ***** enter a loop, keep vold In the daemon state. ** the main task of vold is to run the following two threads: Nm-> Start () and Cl-> startlistener; the two processing threads ** need the framework to act as a bridge and a boss. The framework is the boss that manages these disks. **************************************** **************************************** **/While (1) {sleep (1000);} slogi ("vold exiting"); exit (0 );} /*************************************** **************************************** * ***** the following two functions are not important, that is to say, open the/sys/block directory to handle some things. These two functions are used to confuse vold. ** the social class is relatively low, and O (Social _ classes) O haha. ** There are several functions provided by the bionic library, which are rarely used. **************************************** **************************************** **/Static void do_coldboot (dir * D, int LVL) {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) ;}while (DE = readdir (D ))) {dir * D2; If (de-> d_name [0] = '. ') continue; If (de-> d_type! = Dt_dir & LVL> 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, LVL + 1); closedir (D2 );}}} static void coldboot (const char * path) {dir * D = opendir (PATH); If (d) {do_coldboot (D, 0); closedir (d );}} /*************************************** **************************************** * *** this function is used to parse/etc/vold. fstab configuration file, Text processing. ** different source code versions may be slightly different. ** strsep is a string segmentation function, it can be seen that this function is separated by "\ t" (there is a space before \ t) and separated by space ** or a table. Therefore, spaces in the configuration file can be separated by the tab key; ** strsep is not an ansi c function, but it is used to replace the strtok function. strtok is a thread-insecure function. **************************************** **************************************** **/Static int process_config (volumemanager * VM) {file * FP; int n = 0; char line [255]; If (! (FP = fopen ("/etc/vold. fstab "," R ") {return-1 ;}while (fgets (line, sizeof (line), FP) {char * Next = line; char * type, * label, * mount_point; n ++; line [strlen (line)-1] = '\ 0 '; if (line [0] = '#' | line [0] = '\ 0') continue; If (! (Type = strsep (& next, "\ t") {sloge ("error parsing Type"); goto out_syntax;} If (! (Label = strsep (& next, "\ t") {sloge ("error parsing label"); goto out_syntax;} If (! (Mount_point = strsep (& next, "\ t") {sloge ("error parsing mount point"); goto out_syntax;} If (! Strcmp (type, "dev_mount") {directvolume * DV = NULL; char * part, * sysfs_path; If (! (Part = strsep (& next, "\ t") {sloge ("error parsing partition"); goto out_syntax;} If (strcmp (part, "Auto ") & atoi (Part) = 0) {sloge ("partition must either be 'auto' or 1 Based Index Instead of '% S'", part); goto out_syntax ;} /*************************************** **************************************** * ***** if the configuration file is specified as auto, the storage device is automatically mounted. When the directvolume object is instantiated,-1 ** is passed in. Otherwise, the partition sequence part is passed in; ********************** **************************************** * *******************/If (! Strcmp (part, "Auto") {DV = new directvolume (Vm, label, mount_point,-1);} else {DV = new directvolume (Vm, label, mount_point, atoi (part);} while (sysfs_path = strsep (& next, "\ t "))) {/************************************** **************************************** * ***** Add the storage device to the pathcollection container in the/sys/path, the container is of the "char *" type. ** the hot swapping events of storage devices can be obtained in/sys, therefore, the main task of the directvolume class is to obtain uevent events for ** here; ** directvolume: The handleblockevent (netlinkevent * EVT) function obtains these events, mainly from the kernel of the ** netlinklistener class. **************************************** **************************************** **/If (DV-> addpath (sysfs_path )) {sloge ("failed to add devpath % s to volume % s", sysfs_path, label); goto out_fail ;}} /*************************************** **************************************** * ***** if the correct mounting parameters are found in the configuration file, the directvolume object will be added to the volumecollection ** container, which stores volume * type data. The volumemanager object VM is used to manage these storage devices; ** a storage device A volume object will be instantiated, but for mobile phones, only one SD card can be identified. **************************************** **************************************** **/Vm-> addvolume (DV );} else if (! Strcmp (type, "map_mount") {} else {sloge ("unknown type '% S'", type); goto out_syntax ;}} fclose (FP); Return 0; /*************************************** **************************************** * ***** we can see from the error handling of this main function, this efficient goto technique is often used in system source code. Goto errors are frequently handled in ** systems. It can be said that almost every file uses the Goto jump function; ** many articles or textbooks often refer to negative criticism of the irregular Goto, but from the open source code of these foreign countries, we can see that ** the cool guys like to use Goto, it looks pretty to use goto to handle errors. ** I don't think it can be explained to comment on the advantages and disadvantages of these languages from a practical point of view. So that the code can be more readable by using goto when many errors are handled, reduce the amount of code for repeated error judgments. **************************************** **************************************** **/Out_syntax: sloge ("syntax error on config line % d", n); errno =-einval; out_fail: fclose (FP); Return-1 ;}
In the next article, we will start to analyze the process from the main function entry point ..