Android vold核心篇(VolumeManager)

在我的前一遍博文:Androidvold启动篇中解析了vold如何获取内核发送的热插拔消息,并传递到了VolumeManager的handleBlockEvent函数中。

一、VolumeManager对上层传来的消息处理

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
    }
}
代码中VolumeCollection为Volume的集合,在循环体中(*it)->handleBlockEvent(evt)调用的是Volume的handleBlockEvent函数,但是Volume对该函数的实现如下:

int Volume::handleBlockEvent(NetlinkEvent *evt) {
    errno = ENOSYS;
    return -1;
}
这下我们得回到第一篇的Main.cpp的main函数的process_config中,该函数有这么一段:

dv = new DirectVolume(vm, &(fstab->recs[i]), flags);

if (dv->addPath(fstab->recs[i].blk_device)) {
    SLOGE("Failed to add devpath %s to volume %s",
        fstab->recs[i].blk_device, fstab->recs[i].label);
        goto out_fail;
     }

vm->addVolume(dv);
通过此代码可知,从vold.fstab文件中读取到的volume设备都以DirectVolume对象的方式插入到了VolumeManager中进行管理。

而DirectVolume从Volume类派生而来,所以我们就应该去看DirectVolume的handleBlockEvent函数。

二、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))) {//根据消息的设备路径过滤volume设备
            /* 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);
                }
                /* Send notification iff disk is ready (ie all partitions found) */
                if (getState() == Volume::State_Idle) {
                    char msg[255];

                    snprintf(msg, sizeof(msg),
                             "Volume %s %s disk inserted (%d:%d)", getLabel(),
                             getFuseMountpoint(), mDiskMajor, mDiskMinor);
                    mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,
                                                         msg, false);
                }
            } 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;
}

通过以上代码可知,handleBlockEvent函数对消息进行如下处理:

1、根据设备路径过滤了跟消息无关的设备;

2、根据action来判断事件类型,处理了一下三类事件:

NlActionAdd;
NlActionRemove;
NlActionChange;

3、事件类型确定后,调用相关函数做处理,此处只分析handlePartitionAdded函数的主要代码:

 if (getState() != Volume::State_Formatting) {
            setState(Volume::State_Idle);
            if (mRetryMount == true) {
                mRetryMount = false;
                mountVol();
            }
        }
此处,实际调用的是mountVol函数,源代码太多,截取关键代码:

挂载代码:

if (Fat::doMount(devicePath, getMountpoint(), false, false, false,
                AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) {
            SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno));
            continue;
        }
setState(Volume::State_Mounted);

setState的关键代码如下:

mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeStateChange,
                                         msg, false);

此处为通过套接字向Framework层发送volume状态改变的消息,具体是怎么实现的呢?

这里调用了VolumeManager的mBroadcaster变量的sendBroadcast函数,通过该函数调用mClients成员变量的套接字来发送,

而这个mClients以及跟它相关的套接字是如何来的呢?


请看下文分解:vold与Framework的通讯实现原理








你可能感兴趣的:(Android,基础知识)