MountService启动之后 ,一切准备工作都 做好了,就等待碰上u盘插上了,
这里要讲的是内核发信息给vold,我们在 vold启动这篇曾讲到过注册了一个到内核的UEVENT事件,当有u盘插入的时候,我们就能从这个套接字上收到内核所发出的消息了,这样就开始了vold的消息处理。
先看下消息处理的流程:
在SocketListener::runListener()函数 中,我们一直在select,等待某个连接的到来或者已经的套接字上数据的到来,看下代码:
if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { SLOGE("select failed (%s)", strerror(errno)); sleep(1); continue; } else if (!rc) continue; if (FD_ISSET(mCtrlPipe[0], &read_fds)) break; if (mListen && FD_ISSET(mSock, &read_fds)) { struct sockaddr addr; socklen_t alen = sizeof(addr); int c; if ((c = accept(mSock, &addr, &alen)) < 0) { SLOGE("accept failed (%s)", strerror(errno)); sleep(1); continue; } pthread_mutex_lock(&mClientsLock); mClients->push_back(new SocketClient(c)); pthread_mutex_unlock(&mClientsLock); } do { pthread_mutex_lock(&mClientsLock); for (it = mClients->begin(); it != mClients->end(); ++it) { int fd = (*it)->getSocket(); if (FD_ISSET(fd, &read_fds)) { pthread_mutex_unlock(&mClientsLock); if (!onDataAvailable(*it)) { close(fd); pthread_mutex_lock(&mClientsLock); delete *it; it = mClients->erase(it); pthread_mutex_unlock(&mClientsLock); } FD_CLR(fd, &read_fds); pthread_mutex_lock(&mClientsLock); continue; } } pthread_mutex_unlock(&mClientsLock); } while (0); }当某个套接字上有数据到来时,首先看这个套接字是不是listen的那个套接字,如果是则接收 连接并加到mClients链表中,否则说明某个套接字上有数据到来,这时里是我们注册到内核的那个套接字,调用 onDataAvailable函数,这里由于多态调用的是NetlinkListener::onDataAvailable中的这个函数:
bool NetlinkListener::onDataAvailable(SocketClient *cli) { int socket = cli->getSocket(); int count; if ((count = recv(socket, mBuffer, sizeof(mBuffer), 0)) < 0) { SLOGE("recv failed (%s)", strerror(errno)); return false; } NetlinkEvent *evt = new NetlinkEvent(); if (!evt->decode(mBuffer, count)) { SLOGE("Error decoding NetlinkEvent"); goto out; } onEvent(evt); out: delete evt; return true; }
调用recv接收数据,接着new一个NetlinkEvent并调用它的 decode函数对收到的数据进行解析:
bool NetlinkEvent::decode(char *buffer, int size) { char *s = buffer; char *end; int param_idx = 0; int i; int first = 1; end = s + size; while (s < end) { if (first) { char *p; for (p = s; *p != '@'; p++); p++; mPath = strdup(p); first = 0; } else { if (!strncmp(s, "ACTION=", strlen("ACTION="))) { char *a = s + strlen("ACTION="); if (!strcmp(a, "add")) mAction = NlActionAdd; else if (!strcmp(a, "remove")) mAction = NlActionRemove; else if (!strcmp(a, "change")) mAction = NlActionChange; } else if (!strncmp(s, "SEQNUM=", strlen("SEQNUM="))) mSeq = atoi(s + strlen("SEQNUM=")); else if (!strncmp(s, "SUBSYSTEM=", strlen("SUBSYSTEM="))) mSubsystem = strdup(s + strlen("SUBSYSTEM=")); else mParams[param_idx++] = strdup(s); } s+= strlen(s) + 1; } return true; }这里会对消息进行解析,解析出ACTION、DEVPATH、SUBSYSTEM等等,下面看一下我抓的 一个u盘插入抓的log:
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 D/NetlinkEvent( 946): s = ACTION=add 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 D/NetlinkEvent( 946): s = SUBSYSTEM=block D/NetlinkEvent( 946): s = MAJOR=8 D/NetlinkEvent( 946): s = MINOR=0 D/NetlinkEvent( 946): s = DEVNAME=sda D/NetlinkEvent( 946): s = DEVTYPE=disk D/NetlinkEvent( 946): s = NPARTS=1 D/NetlinkEvent( 946): s = SEQNUM=1058 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 D/NetlinkEvent( 1206): s = SUBSYSTEM=block D/NetlinkEvent( 1206): s = MAJOR=8 D/NetlinkEvent( 1206): s = MINOR=1 D/NetlinkEvent( 1206): s = DEVNAME=sda1 D/NetlinkEvent( 1206): s = DEVTYPE=partition D/NetlinkEvent( 1206): s = PARTN=1 D/NetlinkEvent( 1206): s = SEQNUM=1059这个u盘只有一个分区,下面是有两个分区的log(一部分):
D/NetlinkEvent( 1207): s = ACTION=add 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 D/NetlinkEvent( 1207): s = SUBSYSTEM=block D/NetlinkEvent( 1207): s = MAJOR=8 D/NetlinkEvent( 1207): s = MINOR=16 D/NetlinkEvent( 1207): s = DEVNAME=sdb D/NetlinkEvent( 1207): s = DEVTYPE=disk D/NetlinkEvent( 1207): s = NPARTS=2 D/NetlinkEvent( 1207): s = SEQNUM=1086可以看到,从内核收到的消息中我们能获得很多的信息。
解析完后,就调用onEvent函数对消息进行处理,这里调用的是NetlinkHandler的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); } else if (!strcmp(subsys, "switch")) { vm->handleSwitchEvent(evt); } else if (!strcmp(subsys, "usb_composite")) { vm->handleUsbCompositeEvent(evt); } else if (!strcmp(subsys, "battery")) { } else if (!strcmp(subsys, "power_supply")) { } }从上面 的log可以看出这里获取的subsys是block,所以调用 handleBlockEvent函数
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) { const char *devpath = evt->findParam("DEVPATH"); /* Lookup a volume to handle this device */ VolumeCollection::iterator it; bool hit = false; for (it = mVolumes->begin(); it != mVolumes->end(); ++it) { if (!(*it)->handleBlockEvent(evt)) { #ifdef NETLINK_DEBUG SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel()); #endif hit = true; break; } } if (!hit) { #ifdef NETLINK_DEBUG SLOGW("No volumes handled block event for '%s'", devpath); #endif } }mVolumes中我们在初始化的时候往里面add了 个DirectVolume,所以这里调用DirectVolume::handleBlockEvent
int DirectVolume::handleBlockEvent(NetlinkEvent *evt) { const char *dp = evt->findParam("DEVPATH"); PathCollection::iterator it; for (it = mPaths->begin(); it != mPaths->end(); ++it) { if (!strncmp(dp, *it, strlen(*it))) { /* We can handle this disk */ int action = evt->getAction(); const char *devtype = evt->findParam("DEVTYPE"); if (action == NetlinkEvent::NlActionAdd) { int major = atoi(evt->findParam("MAJOR")); int minor = atoi(evt->findParam("MINOR")); char nodepath[255]; snprintf(nodepath, sizeof(nodepath), "/dev/block/vold/%d:%d", major, minor); if (createDeviceNode(nodepath, major, minor)) { SLOGE("Error making device node '%s' (%s)", nodepath, strerror(errno)); } if (!strcmp(devtype, "disk")) { handleDiskAdded(dp, evt); } else { handlePartitionAdded(dp, evt); } } else if (action == NetlinkEvent::NlActionRemove) { if (!strcmp(devtype, "disk")) { handleDiskRemoved(dp, evt); } else { handlePartitionRemoved(dp, evt); } } else if (action == NetlinkEvent::NlActionChange) { if (!strcmp(devtype, "disk")) { handleDiskChanged(dp, evt); } else { handlePartitionChanged(dp, evt); } } else { SLOGW("Ignoring non add/remove/change event"); } return 0; } } errno = ENODEV; return -1; }
ev_mount sdcard /mnt/sdcard auto /devices/platform/hiusb-ehci.0 /devices/platform/hi_godbox-ehci.0
void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) { mDiskMajor = atoi(evt->findParam("MAJOR")); mDiskMinor = atoi(evt->findParam("MINOR")); const char *tmp = evt->findParam("NPARTS"); if (tmp) { mDiskNumParts = atoi(tmp); } else { SLOGW("Kernel block uevent missing 'NPARTS'"); mDiskNumParts = 1; } char msg[255]; int partmask = 0; int i; for (i = 1; i <= mDiskNumParts; i++) { partmask |= (1 << i); } mPendingPartMap = partmask; if (mDiskNumParts == 0) { #ifdef PARTITION_DEBUG SLOGD("Dv::diskIns - No partitions - good to go son!"); #endif setState(Volume::State_Idle); } else { #ifdef PARTITION_DEBUG SLOGD("Dv::diskIns - waiting for %d partitions (mask 0x%x)", mDiskNumParts, mPendingPartMap); #endif setState(Volume::State_Pending); } snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)", getLabel(), getMountpoint(), mDiskMajor, mDiskMinor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted, msg, false); }mDiskNumParts 不为0,将Volume的状态设置为State_Pending并向FrameWork层广播VolumeDiskInserted的消息,在setState函数中也会广播VolumeStateChange的消息给上层,接着就是handlePartitionAdded 这里是处理add /block/sda/sda*这样的消息的
void DirectVolume::handlePartitionAdded(const char *devpath, NetlinkEvent *evt) { int major = atoi(evt->findParam("MAJOR")); int minor = atoi(evt->findParam("MINOR")); int part_num; const char *tmp = evt->findParam("PARTN"); if (tmp) { part_num = atoi(tmp); } else { SLOGW("Kernel block uevent missing 'PARTN'"); part_num = 1; } if (part_num > mDiskNumParts) { mDiskNumParts = part_num; } if (major != mDiskMajor) { SLOGE("Partition '%s' has a different major than its disk!", devpath); return; } #ifdef PARTITION_DEBUG SLOGD("Dv:partAdd: part_num = %d, minor = %d\n", part_num, minor); #endif mPartMinors[part_num -1] = minor; mPendingPartMap &= ~(1 << part_num); if (!mPendingPartMap) { #ifdef PARTITION_DEBUG SLOGD("Dv:partAdd: Got all partitions - ready to rock!"); #endif if (getState() != Volume::State_Formatting) { setState(Volume::State_Idle); } } else { #ifdef PARTITION_DEBUG SLOGD("Dv:partAdd: pending mask now = 0x%x", mPendingPartMap); #endif } }