码迷,mamicode.com
首页 > 移动开发 > 详细

android usb挂载分析---vold处理内核消息

时间:2015-10-02 12:28:14      阅读:317      评论:0      收藏:0      [点我收藏+]

标签:

 

android usb挂载分析---vold处理内核消息

分类: u盘挂载

MountService启动之后 ,一切准备工作都 做好了,就等待碰上u盘插上了,

 这里要讲的是内核发信息给vold,我们在 vold启动这篇曾讲到过注册了一个到内核的UEVENT事件,当有u盘插入的时候,我们就能从这个套接字上收到内核所发出的消息了,这样就开始了vold的消息处理。

先看下消息处理的流程:

技术分享

在SocketListener::runListener()函数 中,我们一直在select,等待某个连接的到来或者已经的套接字上数据的到来,看下代码:

 

  1. if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) 0) {  
  2.             SLOGE("select failed (%s)", strerror(errno));  
  3.             sleep(1);  
  4.             continue;  
  5.         } else if (!rc)  
  6.             continue;  
  7.   
  8.         if (FD_ISSET(mCtrlPipe[0], &read_fds))  
  9.             break;  
  10.         if (mListen && FD_ISSET(mSock, &read_fds)) {  
  11.             struct sockaddr addr;  
  12.             socklen_t alen = sizeof(addr);  
  13.             int c;  
  14.   
  15.             if ((c = accept(mSock, &addr, &alen)) 0) {  
  16.                 SLOGE("accept failed (%s)", strerror(errno));  
  17.                 sleep(1);  
  18.                 continue;  
  19.             }  
  20.             pthread_mutex_lock(&mClientsLock);  
  21.             mClients->push_back(new SocketClient(c));  
  22.             pthread_mutex_unlock(&mClientsLock);  
  23.         }  
  24.   
  25.         do {  
  26.             pthread_mutex_lock(&mClientsLock);  
  27.             for (it = mClients->begin(); it != mClients->end(); ++it) {  
  28.                 int fd = (*it)->getSocket();  
  29.                 if (FD_ISSET(fd, &read_fds)) {  
  30.                     pthread_mutex_unlock(&mClientsLock);  
  31.                     if (!onDataAvailable(*it)) {  
  32.                         close(fd);  
  33.                         pthread_mutex_lock(&mClientsLock);  
  34.                         delete *it;  
  35.                         it = mClients->erase(it);  
  36.                         pthread_mutex_unlock(&mClientsLock);  
  37.                     }  
  38.                     FD_CLR(fd, &read_fds);  
  39.                     pthread_mutex_lock(&mClientsLock);  
  40.                     continue;  
  41.                 }  
  42.             }  
  43.             pthread_mutex_unlock(&mClientsLock);  
  44.         } while (0);  
  45.     }  
当某个套接字上有数据到来时,首先看这个套接字是不是listen的那个套接字,如果是则接收 连接并加到mClients链表中,否则说明某个套接字上有数据到来,这时里是我们注册到内核的那个套接字,调用onDataAvailable函数,这里由于多态调用的是NetlinkListener::onDataAvailable中的这个函数:

 

 

  1. bool NetlinkListener::onDataAvailable(SocketClient *cli)  
  2. {  
  3.     int socket = cli->getSocket();  
  4.     int count;  
  5.   
  6.     if ((count = recv(socket, mBuffer, sizeof(mBuffer), 0)) < 0) {  
  7.         SLOGE("recv failed (%s)", strerror(errno));  
  8.         return false;  
  9.     }  
  10.   
  11.     NetlinkEvent *evt = new NetlinkEvent();  
  12.     if (!evt->decode(mBuffer, count)) {  
  13.         SLOGE("Error decoding NetlinkEvent");  
  14.         goto out;  
  15.     }  
  16.   
  17.     onEvent(evt);  
  18. out:  
  19.     delete evt;  
  20.     return true;  
  21. }  

调用recv接收数据,接着new一个NetlinkEvent并调用它的 decode函数对收到的数据进行解析:

 

  1. bool NetlinkEvent::decode(char *buffer, int size) {  
  2.     char *s = buffer;  
  3.     char *end;  
  4.     int param_idx = 0;  
  5.     int i;  
  6.     int first = 1;  
  7.   
  8.     end = s + size;  
  9.     while (s < end) {  
  10.         if (first) {  
  11.             char *p;  
  12.             for (p = s; *p != ‘@‘; p++);  
  13.             p++;  
  14.             mPath = strdup(p);  
  15.             first = 0;  
  16.         } else {  
  17.             if (!strncmp(s, "ACTION=", strlen("ACTION="))) {  
  18.                 char *a = s + strlen("ACTION=");  
  19.                 if (!strcmp(a, "add"))  
  20.                     mAction = NlActionAdd;  
  21.                 else if (!strcmp(a, "remove"))  
  22.                     mAction = NlActionRemove;  
  23.                 else if (!strcmp(a, "change"))  
  24.                     mAction = NlActionChange;  
  25.             } else if (!strncmp(s, "SEQNUM=", strlen("SEQNUM=")))  
  26.                 mSeq = atoi(s + strlen("SEQNUM="));  
  27.             else if (!strncmp(s, "SUBSYSTEM=", strlen("SUBSYSTEM=")))  
  28.                 mSubsystem = strdup(s + strlen("SUBSYSTEM="));  
  29.             else  
  30.                 mParams[param_idx++] = strdup(s);  
  31.         }  
  32.         s+= strlen(s) + 1;  
  33.     }  
  34.     return true;  
  35. }  
这里会对消息进行解析,解析出ACTION、DEVPATH、SUBSYSTEM等等,下面看一下我抓的 一个u盘插入抓的log:

 

 

  1. D/NetlinkEvent(  946): s = add@/devices/platform/hiusb-ehci.0/usb1/1-2/1-2.2/1-2.2:1.0/host1/target1:0:0/1:0:0:0/block/sda  
  2. D/NetlinkEvent(  946): s = ACTION=add  
  3. D/NetlinkEvent(  946): s = DEVPATH=/devices/platform/hiusb-ehci.0/usb1/1-2/1-2.2/1-2.2:1.0/host1/target1:0:0/1:0:0:0/block/sda  
  4. D/NetlinkEvent(  946): s = SUBSYSTEM=block  
  5. D/NetlinkEvent(  946): s = MAJOR=8  
  6. D/NetlinkEvent(  946): s = MINOR=0  
  7. D/NetlinkEvent(  946): s = DEVNAME=sda  
  8. D/NetlinkEvent(  946): s = DEVTYPE=disk  
  9. D/NetlinkEvent(  946): s = NPARTS=1  
  10. D/NetlinkEvent(  946): s = SEQNUM=1058  
  11.   
  12. D/NetlinkEvent( 1206): s = DEVPATH=/devices/platform/hiusb-ehci.0/usb1/1-2/1-2.2/1-2.2:1.0/host1/target1:0:0/1:0:0:0/block/sda/sda1  
  13. D/NetlinkEvent( 1206): s = SUBSYSTEM=block  
  14. D/NetlinkEvent( 1206): s = MAJOR=8  
  15. D/NetlinkEvent( 1206): s = MINOR=1  
  16. D/NetlinkEvent( 1206): s = DEVNAME=sda1  
  17. D/NetlinkEvent( 1206): s = DEVTYPE=partition  
  18. D/NetlinkEvent( 1206): s = PARTN=1  
  19. D/NetlinkEvent( 1206): s = SEQNUM=1059  
这个u盘只有一个分区,下面是有两个分区的log(一部分):

 

 

  1. D/NetlinkEvent( 1207): s = ACTION=add  
  2. D/NetlinkEvent( 1207): s = DEVPATH=/devices/platform/hiusb-ehci.0/usb1/1-2/1-2.2/1-2.2:1.0/host2/target2:0:0/2:0:0:0/block/sdb  
  3. D/NetlinkEvent( 1207): s = SUBSYSTEM=block  
  4. D/NetlinkEvent( 1207): s = MAJOR=8  
  5. D/NetlinkEvent( 1207): s = MINOR=16  
  6. D/NetlinkEvent( 1207): s = DEVNAME=sdb  
  7. D/NetlinkEvent( 1207): s = DEVTYPE=disk  
  8. D/NetlinkEvent( 1207): s = NPARTS=2  
  9. D/NetlinkEvent( 1207): s = SEQNUM=1086  
可以看到,从内核收到的消息中我们能获得很多的信息。

 

解析完后,就调用onEvent函数对消息进行处理,这里调用的是NetlinkHandler的onEvent函数:

 

  1. void NetlinkHandler::onEvent(NetlinkEvent *evt) {  
  2.     VolumeManager *vm = VolumeManager::Instance();  
  3.     const char *subsys = evt->getSubsystem();  
  4.   
  5.     if (!subsys) {  
  6.         SLOGW("No subsystem found in netlink event");  
  7.         return;  
  8.     }  
  9.   
  10.     if (!strcmp(subsys, "block")) {  
  11.         vm->handleBlockEvent(evt);  
  12.     } else if (!strcmp(subsys, "switch")) {  
  13.         vm->handleSwitchEvent(evt);  
  14.     } else if (!strcmp(subsys, "usb_composite")) {  
  15.         vm->handleUsbCompositeEvent(evt);  
  16.     } else if (!strcmp(subsys, "battery")) {  
  17.     } else if (!strcmp(subsys, "power_supply")) {  
  18.     }  
  19. }  
从上面 的log可以看出这里获取的subsys是block,所以调用handleBlockEvent函数 

 

  1. void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {  
  2.     const char *devpath = evt->findParam("DEVPATH");  
  3.   
  4.     /* Lookup a volume to handle this device */  
  5.     VolumeCollection::iterator it;  
  6.     bool hit = false;  
  7.     for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {  
  8.         if (!(*it)->handleBlockEvent(evt)) {  
  9. #ifdef NETLINK_DEBUG  
  10.             SLOGD("Device ‘%s‘ event handled by volume %s\n", devpath, (*it)->getLabel());  
  11. #endif  
  12.             hit = true;  
  13.             break;  
  14.         }  
  15.     }  
  16.   
  17.     if (!hit) {  
  18. #ifdef NETLINK_DEBUG  
  19.         SLOGW("No volumes handled block event for ‘%s‘", devpath);  
  20. #endif  
  21.     }  
  22. }  
mVolumes中我们在初始化的时候往里面add了 个DirectVolume,所以这里调用DirectVolume::handleBlockEvent

 

 

  1. int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {  
  2.     const char *dp = evt->findParam("DEVPATH");  
  3.   
  4.     PathCollection::iterator  it;  
  5.     for (it = mPaths->begin(); it != mPaths->end(); ++it) {  
  6.         if (!strncmp(dp, *it, strlen(*it))) {  
  7.             /* We can handle this disk */  
  8.             int action = evt->getAction();  
  9.             const char *devtype = evt->findParam("DEVTYPE");  
  10.   
  11.             if (action == NetlinkEvent::NlActionAdd) {  
  12.                 int major = atoi(evt->findParam("MAJOR"));  
  13.                 int minor = atoi(evt->findParam("MINOR"));  
  14.                 char nodepath[255];  
  15.   
  16.                 snprintf(nodepath,  
  17.                          sizeof(nodepath), "/dev/block/vold/%d:%d",  
  18.                          major, minor);  
  19.                 if (createDeviceNode(nodepath, major, minor)) {  
  20.                     SLOGE("Error making device node ‘%s‘ (%s)", nodepath,  
  21.                                                                strerror(errno));  
  22.                 }  
  23.                 if (!strcmp(devtype, "disk")) {  
  24.                     handleDiskAdded(dp, evt);  
  25.                 } else {  
  26.                     handlePartitionAdded(dp, evt);  
  27.                 }  
  28.             } else if (action == NetlinkEvent::NlActionRemove) {  
  29.                 if (!strcmp(devtype, "disk")) {  
  30.                     handleDiskRemoved(dp, evt);  
  31.                 } else {  
  32.                     handlePartitionRemoved(dp, evt);  
  33.                 }  
  34.             } else if (action == NetlinkEvent::NlActionChange) {  
  35.                 if (!strcmp(devtype, "disk")) {  
  36.                     handleDiskChanged(dp, evt);  
  37.                 } else {  
  38.                     handlePartitionChanged(dp, evt);  
  39.                 }  
  40.             } else {  
  41.                     SLOGW("Ignoring non add/remove/change event");  
  42.             }  
  43.   
  44.             return 0;  
  45.         }  
  46.     }  
  47.     errno = ENODEV;  
  48.     return -1;  
  49. }  

mPaths我们在parse vold.fstab把相应的解析到的路径添加进去了,我们看下这个脚本:

 

 

  1. ev_mount sdcard /mnt/sdcard auto /devices/platform/hiusb-ehci.0 /devices/platform/hi_godbox-ehci.0  

这里add的路径正好和上面 log打出来的路径相匹配,首先执行的handleDiskAdded,也就是在收到这样的消息的时候,提示有磁盘插入:

 

 

  1. void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) {  
  2.     mDiskMajor = atoi(evt->findParam("MAJOR"));  
  3.     mDiskMinor = atoi(evt->findParam("MINOR"));  
  4.   
  5.     const char *tmp = evt->findParam("NPARTS");  
  6.     if (tmp) {  
  7.         mDiskNumParts = atoi(tmp);  
  8.     } else {  
  9.         SLOGW("Kernel block uevent missing ‘NPARTS‘");  
  10.         mDiskNumParts = 1;  
  11.     }  
  12.   
  13.     char msg[255];  
  14.   
  15.     int partmask = 0;  
  16.     int i;  
  17.     for (i = 1; i <= mDiskNumParts; i++) {  
  18.         partmask |= (1 << i);  
  19.     }  
  20.     mPendingPartMap = partmask;  
  21.   
  22.     if (mDiskNumParts == 0) {  
  23. #ifdef PARTITION_DEBUG  
  24.         SLOGD("Dv::diskIns - No partitions - good to go son!");  
  25. #endif  
  26.         setState(Volume::State_Idle);  
  27.     } else {  
  28. #ifdef PARTITION_DEBUG  
  29.         SLOGD("Dv::diskIns - waiting for %d partitions (mask 0x%x)",  
  30.              mDiskNumParts, mPendingPartMap);  
  31. #endif  
  32.         setState(Volume::State_Pending);  
  33.     }  
  34.   
  35.     snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)",  
  36.              getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);  
  37.     mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,  
  38.                                              msg, false);  
  39. }  
mDiskNumParts 不为0,将Volume的状态设置为State_Pending并向FrameWork层广播VolumeDiskInserted的消息,在setState函数中也会广播VolumeStateChange的消息给上层,接着就是handlePartitionAdded 这里是处理add /block/sda/sda*这样的消息的

 

 

  1. void DirectVolume::handlePartitionAdded(const char *devpath, NetlinkEvent *evt) {  
  2.     int major = atoi(evt->findParam("MAJOR"));  
  3.     int minor = atoi(evt->findParam("MINOR"));  
  4.   
  5.     int part_num;  
  6.   
  7.     const char *tmp = evt->findParam("PARTN");  
  8.   
  9.     if (tmp) {  
  10.         part_num = atoi(tmp);  
  11.     } else {  
  12.         SLOGW("Kernel block uevent missing ‘PARTN‘");  
  13.         part_num = 1;  
  14.     }  
  15.   
  16.     if (part_num > mDiskNumParts) {  
  17.         mDiskNumParts = part_num;  
  18.     }  
  19.   
  20.     if (major != mDiskMajor) {  
  21.         SLOGE("Partition ‘%s‘ has a different major than its disk!", devpath);  
  22.         return;  
  23.     }  
  24. #ifdef PARTITION_DEBUG  
  25.     SLOGD("Dv:partAdd: part_num = %d, minor = %d\n", part_num, minor);  
  26. #endif  
  27.     mPartMinors[part_num -1] = minor;  
  28.   
  29.     mPendingPartMap &= ~(1 << part_num);  
  30.     if (!mPendingPartMap) {  
  31. #ifdef PARTITION_DEBUG  
  32.         SLOGD("Dv:partAdd: Got all partitions - ready to rock!");  
  33. #endif  
  34.         if (getState() != Volume::State_Formatting) {  
  35.             setState(Volume::State_Idle);  
  36.         }  
  37.     } else {  
  38. #ifdef PARTITION_DEBUG  
  39.         SLOGD("Dv:partAdd: pending mask now = 0x%x", mPendingPartMap);  
  40. #endif  
  41.     }  
  42. }  

当mPendingPartMap减为0时,这时Volume的状态不为State_Formatting,将广播一条VolumeStateChange的消息。
到这里,内核的消息基本就处理完了,当然这里讲的只是add的消息,还有remove,change消息等。。。这里就不做介绍了。
 

android usb挂载分析---vold处理内核消息

标签:

原文地址:http://www.cnblogs.com/senior-engineer/p/4852079.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!