Storage System of Android-Vold and MountService analysis (3), voldmountservice

Source: Internet
Author: User

Storage System of Android-Vold and MountService analysis (3), voldmountservice

Android storage system (III)

Review:The previous post analyzed the main () function of Vold and the function call process of NetlinkManager. As of the creation of NetlinkHandler and start () call, this post continues to analyze the source code.

 

 

1. process block-type uevent

The main () function creates the CommandListener object, and the start () function of NetlinkManager creates the NetlinkHandler object. If the inheritance relationship between the CommandListener class and the NetlinkHandler class is illustrated, they are all derived from the SocketListener class, as shown in:

 

Figure 1 inheritance relationship between NetlinkHandler and CommandListener

Principle: The bottom-layer SocketListener class listens to socket data and sends the received data to functions of the FrameworkListener class and the NetlinkListener class respectively, analyze the data from the Framework and driver, and then call the functions in CommandListener and NetlinkHandler Based on the command.

Observe the construction method of the NetlinkHandler class. The Code is as follows:

NetlinkHandler::NetlinkHandler(int listenerSocket) :                NetlinkListener(listenerSocket) {}

This construction method is very simple. Let's look at its start () method. The Code is as follows:

int NetlinkHandler::start() {    return this->startListener();}

The start () method calls the startListener () function of SocketListener. The Code is as follows:

1 int SocketListener: startListener (int backlog) {2 if (! MSocketName & mSock =-1) {3 SLOGE ("Failed to start unbound listener"); 4 errno = EINVAL; 5 return-1; 6} else if (mSocketName) {// only the CommandListener will set mSocketName 7 if (mSock = android_get_control_socket (mSocketName) <0) {8 SLOGE ("Obtaining file descriptor socket '% s' failed: % s ", mSocketName, strerror (errno); 9 return-1; 10} 11 SLOGV (" got mSock = % d for % s ", mSock, mSocketName ); 12} 13 1 4 if (mListen & listen (mSock, backlog) <0) {15 SLOGE ("Unable to listen on socket (% s)", strerror (errno )); 16 return-1; 17} else if (! MListen) 18 mClients-> push_back (new SocketClient (mSock, false, musew.num); 19 20 if (pipe (mCtrlPipe) {// create an MPS queue, used to exit the listening thread 21 SLOGE ("pipe failed (% s)", strerror (errno); 22 return-1; 23} 24 25 if (pthread_create (& mThread, NULL, socketListener: threadStart, this) {// create a listening thread 26 SLOGE ("pthread_create (% s)", strerror (errno); 27 return-1; 28} 29 30 return 0; 31}

The startListener () function starts to listen to the socket. This function is called in NetlinkHandler and in CommandListener.

The startListener () function first checks whether the variable mSocketName has a value. Only the CommandListener object assigns a value to this variable. Its value is the socket string defined in init. rc.

The purpose of calling the android_get_control_socket () function is to obtain the socket value from the environment variable, so that the CommandListener object obtains the socket to be listened,

For the NetlinkHandler object, its mSocket is not NULL and a socket has been created before.

 

The startListener () function then checks whether to call the Listen () function to Listen to the socket based on the value of the member variable mListener. The value of this mListen is initialized based on parameters when the object is constructed.

For a CommandListener object, the value of mListener is true. For a NetlinkHandler object, the value of mListener is false. This is because the CommandListener object communicates with the SystemServer and needs to listen for socket connections, while the NetlinkHandler object does not.

  

The startListener () function will create an MPS queue to notify the thread to stop listening. This thread is the listener thread created at the end of startListener () function, its running function is threadStart (). In the previous NetlinkManager family diagram, we can clearly find that the Code is as follows:

Void * SocketListener: threadStart (void * obj) {SocketListener * me = reinterpret_cast <SocketListener *> (obj); me-> runListener (); // call runListener () method pthread_exit (NULL); return NULL ;}

ThreadStart () calls the runListener () function again. The Code is as follows:

1 void SocketListener: runListener () {2 3 SocketClientCollection pendingList; 4 5 while (1) {// infinite loop, always listen to 6 SocketClientCollection: iterator it; 7 fd_set read_fds; 8 int rc = 0; 9 int max =-1; 10 11 FD_ZERO (& read_fds); // clear the file descriptor set read_fds12 13 if (mListen) {// if you need to listen to 14 max = mSock; 15 FD_SET (mSock, & read_fds); // Add mSock to read_fds16} 17 18 FD_SET (mCtrlPipe [0], & read_fds); // Add the MPs queue mCtrlPipe [0] to rea. D_fds19 if (mCtrlPipe [0]> max) 20 max = mCtrlPipe [0]; 21 22 pthread_mutex_lock (& mClientsLock ); // Lock 23 for (it = mClients-> begin (); it! = MClients-> end (); ++ it) {// The socket of the NetlinkHandler object is saved in mClient, or the socket24 int fd = (* it) accessed by CommandListener) -> getSocket (); 25 FD_SET (fd, & read_fds); // traverses all the members of the mClients container and calls the inline function getSocket () to obtain the file descriptor, add it to the file descriptor set read_fds26 if (fd> max) {// Add it to read_fds27 max = fd; 28} 29} 30 pthread_mutex_unlock (& mClientsLock ); 31 SLOGV ("mListen = % d, max = % d, mSocketName = % s", mListen, max, mSocketName); 32 if (rc = select (m Ax + 1, & read_fds, NULL) <0) {// execute the select call and start waiting for data on the socket to arrive. 33 if (errno = EINTR) // exit select due to interruption, continue 34 continue; 35 SLOGE ("select failed (% s) mListen = % d, max = % d", strerror (errno), mListen, max); 36 sleep (1); // select error, continue 37 continue after 1 second of sleep; 38} else if (! Rc) 39 continue; // if no data arrives on fd, continue 40 41 if (FD_ISSET (mCtrlPipe [0], & read_fds) {42 char c = CtrlPipe_Shutdown; 43 TEMP_FAILURE_RETRY (read (mCtrlPipe [0], & c, 1); 44 if (c = CtrlPipe_Shutdown) {45 break; 46} 47 continue; 48} 49 if (mListen & FD_ISSET (mSock, & read_fds) {// if there is a connection request for 50 struct sockaddr addr; 51 socklen_t alen; 52 int c; 53 54 do {55 alen = sizeof (addr); 56 c = accept (mSock, & Addr, & alen); // Access Connection Request 57 SLOGV ("% s got % d from accept", mSocketName, c ); 58} while (c <0 & errno = EINTR); // re-access 59 if (c <0) {60 SLOGE ("accept failed (% s)", strerror (errno); 61 sleep (1); 62 continue; // access error, continue loop 63} 64 pthread_mutex_lock (& mClientsLock); 65 mClients-> push_back (new SocketClient (c, true, musew.num); // Add the connected socket connection to mClients, in this way, the collected data reaches 66 pthread_mutex_unlo. Ck (& mClientsLock); 67} 68 69/* Add all active clients to the pending list first */70 pendingList. clear (); 71 pthread_mutex_lock (& mClientsLock); 72 for (it = mClients-> begin (); it! = MClients-> end (); ++ it) {73 SocketClient * c = * it; 74 int fd = c-> getSocket (); 75 if (FD_ISSET (fd, & read_fds) {76 pendingList. push_back (c); // If data exists in a socket in mClients, add it to the pendingList 77 c-> incRef (); 78} 79} 80 pthread_mutex_unlock (& mClientsLock); 81 82/* Process the pending list, since it is owned by the thread, * there is no need to lock it */83 while (! PendingList. empty () {// process pendingList list 84/* Pop the first item from the list */85 it = pendingList. begin (); 86 SocketClient * c = * it; 87 pendingList. erase (it); // Delete the processed socket from the pendingList 88/* Process it, if false is returned, remove from list */89 if (! OnDataAvailable (c) {90 release (c, false); // call the release () function --> call onDataAvailable () method 91} 92 c-> decRef (); 93} 94} 95}

SocketListener: runListener is a function actually executed by a thread.

Although the above runListener () function is relatively long, it is a piece of standard code for handling mixed socket connections. It is very helpful for us to compile the socket program. Here is a simple introduction.

 

<-------- Next, let's continue to analyze... -------->

 

After the runListener () function receives the data transmitted from the driver or MountService, it calls the onDataAvailable () function to process the data. Both the FrameworkListener class and the NetlinkListener class will reload this function.

  First, let's analyze how the onDataAvailable () function of the NetlinkListener class is implemented!

Directly run the Code:

1 bool NetlinkListener: onDataAvailable (SocketClient * cli) 2 {3 int socket = cli-> getSocket (); 4 ssize_t count; 5 uid_t uid =-1; 6/* read the uevent message sent by the kernel from the socket */7 count = TEMP_FAILURE_RETRY (uevent_kernel_multicast_uid_recv (socket, mBuffer, sizeof (mBuffer), & uid )); 8 if (count <0) {// if count <0, handle errors 9 if (uid> 0) 10 LOG_EVENT_INT (65537, uid); 11 return false; 12} 13 14 NetlinkEvent * evt = new NetlinkEvent (); // create a NetlinkEvent object 15 if (evt-> decode (mBuffer, count, mFormat) {// call decode () function 16OnEvent (evt );// Implement 17} else if (mFormat! In NetlinkHandler! = NETLINK_FORMAT_BINARY) {18 SLOGE ("Error decoding NetlinkEvent"); 19} 20 delete evt; 21 return true; 22}

The onDataAvailable () function of the NetlinkListener class first calls the uevent_kernel_multicast_uid_recv () function to receive uevent messages.

After receiving a message, a NetlinkEvent object is created, and its decode () function is called to decode the message. Then, the obtained message data is assigned a value to the member variable of the NetlinkEvent object.

Finally, the onDataAvailable () function calls the onEvent () function to continue message processing. The onEvent () function code is as follows:

Void NetlinkHandler: onEvent (NetlinkEvent * evt) {VolumeManager * vm = VolumeManager: Instance (); const char * subsys = evt-> getSubsystem (); if (! Subsys) {SLOGW ("No subsystem found in netlink event"); return;} if (! Strcmp (subsys, "block") {vm-> handleBlockEvent (evt); // call the handleBlockEvent () function of VolumeManager for processing }}

The onEvent () function of NetlinkHandler determines which subsystem the event belongs to. If it belongs to a "block" (SD hot swapping), it calls the handleBlockEvent () function of VolumeManager for processing. The Code is as follows:

Void VolumeManager: handleBlockEvent (NetlinkEvent * evt) {const char * devpath = evt-> findParam ("DEVPATH"); VolumeCollection: iterator it; bool hit = false; for (it = mVolumes-> begin (); it! = MVolumes-> end (); ++ it) {if (! (* It)-> handleBlockEvent (evt) {// For each DirectVolume object, call handleBlockEvent to process the event hit = true; // If a Volume object processes the Event, returns break ;}}.....}

Summary:The source code of this post is analyzed here first. The next post analyzes the handleBlockEvent () function of the DirectVolume object and how the CommandListener object processes command data sent from MountService, that is, we have not discussed the code about the onDataAvailable () function of FrameworkListener!

PS: coders interested in Android mobile phone development, IOS, and games (pure interest, cabbage) and Java EE, in this way, I can see your work and experience in time. Thank you!

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.