Android的存储系统—Vold与MountService分析
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android的存储系统—Vold与MountService分析相关的知识,希望对你有一定的参考价值。
Android的存储系统(三)
回顾:前帖分析了Vold的main()函数和NetlinkManager的函数调用流程,截止到NetlinkHandler的创建和start()调用,本帖继续分析源码 |
1、处理block类型的uevent
main()函数创建了CommandListener对象,NetlinkManager的start()函数又创建了NetlinkHandler对象,如果将CommandListener类和NetlinkHandler类的继承关系图画出来,会发现它们都是从SocketListener类派生出来的,如下图所示:
图1 NetlinkHandler和CommandListener的继承关系
原理:处于最底层的SocketListener类的作用是监听socket的数据,接收到数据后分别交给FrameworkListener类和NetlinkListener类的函数,并分别对来自Framework和驱动的数据进行分析,分析后根据命令再分别调用CommandListener和NetlinkHandler中的函数。
观察NetlinkHandler类的构造方法,代码如下:
NetlinkHandler::NetlinkHandler(int listenerSocket) : NetlinkListener(listenerSocket) { }
这个构造方法很简单,再看看它的start()方法,代码如下:
int NetlinkHandler::start() { return this->startListener(); }
可以发现,start()方法调用了SocketListener的startListener()函数,代码如下:
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) { // 只有CommandListener中会设置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 14 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, mUseCmdNum)); 19 20 if (pipe(mCtrlPipe)) { // 创建管道,用于退出监听线程 21 SLOGE("pipe failed (%s)", strerror(errno)); 22 return -1; 23 } 24 25 if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) { // 创建一个监听线程 26 SLOGE("pthread_create (%s)", strerror(errno)); 27 return -1; 28 } 29 30 return 0; 31 }
startListener()函数开始监听socket,这个函数在NetlinkHandler中会被调用,在CommandListener也会被调用。
startListener()函数首先判断变量mSocketName是否有值,只有CommandListener对象会对这个变量赋值,它的值就是在init.rc中定义的socket字符串。
调用函数 android_get_control_socket()的目的是从环境变量中取得socket的值,这样CommandListener对象得到了它需要监听的socket,
而对于NetlinkHandler对象而言,它的mSocket不为NULL,前面已经创建了socket。
startListener()函数接下来会根据成员变量mListener的值来判断是否需要调用Listen()函数来监听socket。这个mListen的值在对象构造时根据参数来初始化。
对于CommandListener对象,mListener的值为ture,对于NetlinkHandler对象,mListener的值为false,这是因为CommandListener对象和SystemServer通信,需要监听socket连接,而NetlinkHandler对象则不用。
接下来startListener()函数会创建一个管道,这个管道的作用是通知线程停止监听,这个线程就是startListener()函数最后创建的监听线程,它的运行函数是threadStart(),在前贴的NetlinkManager家族图系中我们可以清晰的发现,其代码如下:
void *SocketListener::threadStart(void *obj) { SocketListener *me = reinterpret_cast<SocketListener *>(obj); me->runListener(); // 调用runListener()方法 pthread_exit(NULL); return NULL; }
threadStart()中又调用了runListener()函数,代码如下:
1 void SocketListener::runListener() { 2 3 SocketClientCollection pendingList; 4 5 while(1) { // 无限循环,一直监听 6 SocketClientCollection::iterator it; 7 fd_set read_fds; 8 int rc = 0; 9 int max = -1; 10 11 FD_ZERO(&read_fds); // 清空文件描述符集read_fds 12 13 if (mListen) { // 如果需要监听 14 max = mSock; 15 FD_SET(mSock, &read_fds); // 把mSock加入到read_fds 16 } 17 18 FD_SET(mCtrlPipe[0], &read_fds); // 把管道mCtrlPipe[0]也加入到read_fds 19 if (mCtrlPipe[0] > max) 20 max = mCtrlPipe[0]; 21 22 pthread_mutex_lock(&mClientsLock); // 对容器mClients的操作需要加锁 23 for (it = mClients->begin(); it != mClients->end(); ++it) { // mClient中保存的是NetlinkHandler对象的socket,或者CommandListener接入的socket 24 int fd = (*it)->getSocket(); 25 FD_SET(fd, &read_fds); // 遍历容器mClients的所有成员,调用内联函数getSocket()获取文件描述符,并添加到文件描述符集read_fds 26 if (fd > max) { // 也加入到read_fds 27 max = fd; 28 } 29 } 30 pthread_mutex_unlock(&mClientsLock); 31 SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName); 32 if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { // 执行select调用,开始等待socket上的数据到来 33 if (errno == EINTR) // 因为中断退出select,继续 34 continue; 35 SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max); 36 sleep(1); // select出错,休眠1秒后继续 37 continue; 38 } else if (!rc) 39 continue; // 如果fd上没有数据到达,继续 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)) { // 如果是CommandListener对象上有连接请求 50 struct sockaddr addr; 51 socklen_t alen; 52 int c; 53 54 do { 55 alen = sizeof(addr); 56 c = accept(mSock, &addr, &alen); // 接入连接请求 57 SLOGV("%s got %d from accept", mSocketName, c); 58 } while (c < 0 && errno == EINTR); // 如果是中断导致失败,重新接入 59 if (c < 0) { 60 SLOGE("accept failed (%s)", strerror(errno)); 61 sleep(1); 62 continue; // 接入发生错误,继续循环 63 } 64 pthread_mutex_lock(&mClientsLock); 65 mClients->push_back(new SocketClient(c, true, mUseCmdNum)); // 把接入的socket连接加入到mClients,这样再循环时就会监听到它的数据到达 66 pthread_mutex_unlock(&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); // 如果mClients中的某个socket上有数据了,把它加入到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()) { // 处理pendingList列表 84 /* Pop the first item from the list */ 85 it = pendingList.begin(); 86 SocketClient* c = *it; 87 pendingList.erase(it); // 把处理了的socket从pendingList列表中删除 88 /* Process it, if false is returned, remove from list */ 89 if (!onDataAvailable(c)) { 90 release(c, false); // 调用release()函数-->调用onDataAvailable()方法 91 } 92 c->decRef(); 93 } 94 } 95 }
SocketListener::runListener是线程真正执行的函数。
以上runListener()函数虽然比较长,但这是一段标准的处理混合socket连接的代码,对于我们编写socket的程序大有帮助,这里先做简单了解。
<--------接下来,我们继续分析......-------->
runListener()函数收到从驱动传递的数据或者MountService传递的数据后,调用onDataAvailable()函数来处理,FrameworkListener类和NetlinkListener类都会重载这个函数。
首先来分析一下NetlinkListener类的onDataAvailable()函数是如何实现的!
直接上代码:
1 bool NetlinkListener::onDataAvailable(SocketClient *cli) 2 { 3 int socket = cli->getSocket(); 4 ssize_t count; 5 uid_t uid = -1; 6 /*从socket中读取kernel发送来的uevent消息*/ 7 count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv(socket, mBuffer, sizeof(mBuffer), &uid)); 8 if (count < 0) { // 如果count<0,进行错误处理 9 if (uid > 0) 10 LOG_EVENT_INT(65537, uid); 11 return false; 12 } 13 14 NetlinkEvent *evt = new NetlinkEvent(); // 创建NetlinkEvent对象 15 if (evt->decode(mBuffer, count, mFormat)) { // 调用decode()函数 16 onEvent(evt); // 在NetlinkHandler中实现17 } else if (mFormat != NETLINK_FORMAT_BINARY) { 18 SLOGE("Error decoding NetlinkEvent"); 19 } 20 delete evt; 21 return true; 22 }
NetlinkListener类的onDataAvailable()函数首先调用uevent_kernel_multicast_uid_recv()函数来接收uevent消息。
接收到消息后,会创建NetlinkEvent对象,然后调用它的decode()函数对消息进行解码,然后用得到的消息数据给NetlinkEvent对象的成员变量赋值。
最后onDataAvailable()函数调用了onEvent()函数继续处理消息,onEvent()函数的代码如下:
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); // 调用VolumeManager的handleBlockEvent()函数来处理 } }
NetlinkHandler的onEvent()函数中会判断event属于哪个子系统的,如果属于“block”(SD热插拔),则调用VolumeManager的handleBlockEvent()函数来处理,代码如下:
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)) { // 对每个DirectVolume对象,调用它handleBlockEvent来处理这个event hit = true; // 如果某个Volume对象处理了Event,则返回 break; } } ..... }
总结:本帖的源码分析先到这里为止,下一贴再分析DirectVolume对象的handleBlockEvent()函数以及CommandListener对象如何处理从MountService发送的命令数据,即我们之前还没有讨论的关于FrameworkListener的onDataAvailable()函数的代码! PS:希望对Android手机开发、ios、以及游戏(纯兴趣,白菜)和Java EE感兴趣的码友们互粉,这样我也能及时的看到你们的大神之作和经验之贴,感谢感谢! |
以上是关于Android的存储系统—Vold与MountService分析的主要内容,如果未能解决你的问题,请参考以下文章