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

时间:2023-03-08 16:53:34
android usb挂载分析---vold处理内核消息
分类: u盘挂载2012-03-29 22:25 3215人阅读 评论(0) 收藏 举报

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

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

先看下消息处理的流程:

android usb挂载分析---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. if (FD_ISSET(mCtrlPipe[0], &read_fds))
  8. break;
  9. if (mListen && FD_ISSET(mSock, &read_fds)) {
  10. struct sockaddr addr;
  11. socklen_t alen = sizeof(addr);
  12. int c;
  13. if ((c = accept(mSock, &addr, &alen)) < 0) {
  14. SLOGE("accept failed (%s)", strerror(errno));
  15. sleep(1);
  16. continue;
  17. }
  18. pthread_mutex_lock(&mClientsLock);
  19. mClients->push_back(new SocketClient(c));
  20. pthread_mutex_unlock(&mClientsLock);
  21. }
  22. do {
  23. pthread_mutex_lock(&mClientsLock);
  24. for (it = mClients->begin(); it != mClients->end(); ++it) {
  25. int fd = (*it)->getSocket();
  26. if (FD_ISSET(fd, &read_fds)) {
  27. pthread_mutex_unlock(&mClientsLock);
  28. if (!onDataAvailable(*it)) {
  29. close(fd);
  30. pthread_mutex_lock(&mClientsLock);
  31. delete *it;
  32. it = mClients->erase(it);
  33. pthread_mutex_unlock(&mClientsLock);
  34. }
  35. FD_CLR(fd, &read_fds);
  36. pthread_mutex_lock(&mClientsLock);
  37. continue;
  38. }
  39. }
  40. pthread_mutex_unlock(&mClientsLock);
  41. } while (0);

当某个套接字上有数据到来时,首先看这个套接字是不是listen的那个套接字,如果是则接收 连接并加到mClients链表中,否则说明某个套接字上有数据到来,这时里是我们注册到内核的那个套接字,调用onDataAvailable函数,这里由于多态调用的是NetlinkListener::onDataAvailable中的这个函数:

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

调用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. end = s + size;
  8. while (s < end) {
  9. if (first) {
  10. char *p;
  11. for (p = s; *p != '@'; p++);
  12. p++;
  13. mPath = strdup(p);
  14. first = 0;
  15. } else {
  16. if (!strncmp(s, "ACTION=", strlen("ACTION="))) {
  17. char *a = s + strlen("ACTION=");
  18. if (!strcmp(a, "add"))
  19. mAction = NlActionAdd;
  20. else if (!strcmp(a, "remove"))
  21. mAction = NlActionRemove;
  22. else if (!strcmp(a, "change"))
  23. mAction = NlActionChange;
  24. } else if (!strncmp(s, "SEQNUM=", strlen("SEQNUM=")))
  25. mSeq = atoi(s + strlen("SEQNUM="));
  26. else if (!strncmp(s, "SUBSYSTEM=", strlen("SUBSYSTEM=")))
  27. mSubsystem = strdup(s + strlen("SUBSYSTEM="));
  28. else
  29. mParams[param_idx++] = strdup(s);
  30. }
  31. s+= strlen(s) + 1;
  32. }
  33. return true;
  34. }

这里会对消息进行解析,解析出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. 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
  12. D/NetlinkEvent( 1206): s = SUBSYSTEM=block
  13. D/NetlinkEvent( 1206): s = MAJOR=8
  14. D/NetlinkEvent( 1206): s = MINOR=1
  15. D/NetlinkEvent( 1206): s = DEVNAME=sda1
  16. D/NetlinkEvent( 1206): s = DEVTYPE=partition
  17. D/NetlinkEvent( 1206): s = PARTN=1
  18. 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. if (!subsys) {
  5. SLOGW("No subsystem found in netlink event");
  6. return;
  7. }
  8. if (!strcmp(subsys, "block")) {
  9. vm->handleBlockEvent(evt);
  10. } else if (!strcmp(subsys, "switch")) {
  11. vm->handleSwitchEvent(evt);
  12. } else if (!strcmp(subsys, "usb_composite")) {
  13. vm->handleUsbCompositeEvent(evt);
  14. } else if (!strcmp(subsys, "battery")) {
  15. } else if (!strcmp(subsys, "power_supply")) {
  16. }
  17. }

从上面 的log可以看出这里获取的subsys是block,所以调用handleBlockEvent函数

  1. void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
  2. const char *devpath = evt->findParam("DEVPATH");
  3. /* Lookup a volume to handle this device */
  4. VolumeCollection::iterator it;
  5. bool hit = false;
  6. for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
  7. if (!(*it)->handleBlockEvent(evt)) {
  8. #ifdef NETLINK_DEBUG
  9. SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
  10. #endif
  11. hit = true;
  12. break;
  13. }
  14. }
  15. if (!hit) {
  16. #ifdef NETLINK_DEBUG
  17. SLOGW("No volumes handled block event for '%s'", devpath);
  18. #endif
  19. }
  20. }

mVolumes中我们在初始化的时候往里面add了 个DirectVolume,所以这里调用DirectVolume::handleBlockEvent

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

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. const char *tmp = evt->findParam("NPARTS");
  5. if (tmp) {
  6. mDiskNumParts = atoi(tmp);
  7. } else {
  8. SLOGW("Kernel block uevent missing 'NPARTS'");
  9. mDiskNumParts = 1;
  10. }
  11. char msg[255];
  12. int partmask = 0;
  13. int i;
  14. for (i = 1; i <= mDiskNumParts; i++) {
  15. partmask |= (1 << i);
  16. }
  17. mPendingPartMap = partmask;
  18. if (mDiskNumParts == 0) {
  19. #ifdef PARTITION_DEBUG
  20. SLOGD("Dv::diskIns - No partitions - good to go son!");
  21. #endif
  22. setState(Volume::State_Idle);
  23. } else {
  24. #ifdef PARTITION_DEBUG
  25. SLOGD("Dv::diskIns - waiting for %d partitions (mask 0x%x)",
  26. mDiskNumParts, mPendingPartMap);
  27. #endif
  28. setState(Volume::State_Pending);
  29. }
  30. snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)",
  31. getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);
  32. mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,
  33. msg, false);
  34. }

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

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