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;
- }
mPaths我们在parse vold.fstab把相应的解析到的路径添加进去了,我们看下这个脚本:
- ev_mount sdcard /mnt/sdcard auto /devices/platform/hiusb-ehci.0 /devices/platform/hi_godbox-ehci.0
这里add的路径正好和上面 log打出来的路径相匹配,首先执行的handleDiskAdded,也就是在收到这样的消息的时候,提示有磁盘插入:
- 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
- }
- }
当mPendingPartMap减为0时,这时Volume的状态不为State_Formatting,将广播一条VolumeStateChange的消息。
到这里,内核的消息基本就处理完了,当然这里讲的只是add的消息,还有remove,change消息等。。。这里就不做介绍了。