zoukankan      html  css  js  c++  java
  • android usb挂载分析---vold处理内核消息

     

    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 ", 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 ", 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消息等。。。这里就不做介绍了。
     
  • 相关阅读:
    VOA 2009/11/02 DEVELOPMENT REPORT In Kenya, a Better Life Through Mobile Money
    2009.11.26教育报道在美留学生数量创历史新高
    Java中如何实现Tree的数据结构算法
    The Python Tutorial
    VOA HEALTH REPORT Debate Over New Guidelines for Breast Cancer Screening
    VOA ECONOMICS REPORT Nearly Half of US Jobs Now Held by Women
    VOA ECONOMICS REPORT Junior Achievement Marks 90 Years of Business Education
    VOA 2009/11/07 IN THE NEWS A Second Term for Karzai; US Jobless Rate at 10.2%
    Ant入门
    Python 与系统管理
  • 原文地址:https://www.cnblogs.com/senior-engineer/p/4852079.html
Copyright © 2011-2022 走看看