天天看點

Android SDCard UnMounted 流程分析(二)

 上一篇講到通過NetlinkManager發送uevent 指令到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;

    }

    SLOGD("NetlinkHandler:OnEvent subsys values is %s",subsys);

    if (!strcmp(subsys, "block")) {

        SLOGD("NetlinkHandler:onEvent");

        vm->handleBlockEvent(evt);

複制代碼

 在NetlinkHandler 裡面得一個VolumeManager,當收到的指令為block時調用VolumnManager的handleBlockEvent,如上加紅加粗的代碼。

handleBlockEvent實則是通過一個循環将事先将main事先讀取的配置檔案:etc/vold.fstab存進VolumeCollection,得到VolumeCollection的對象,然後調用Volume 的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) {

        SLOGW("No volumes handled block event for '%s'", devpath);

看一下Volume 的handleblockEvent代碼:

int Volume::handleBlockEvent(NetlinkEvent *evt) {

    errno = ENOSYS;

    return -1;

 看起來好像沒做什麼事,其實真的實作在于Volume 的子類,DirectVolume,DirectVolme 中重寫了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) {

                    handleDiskRemoved(dp, evt);

                    SLOGD("DirectVolume:handleBlockEvent--->handlePartitionRemoved");

                    handlePartitionRemoved(dp, evt);

            } else if (action == NetlinkEvent::NlActionChange) {

                    handleDiskChanged(dp, evt);

                    handlePartitionChanged(dp, evt);

            } else {

                    SLOGW("Ignoring non add/remove/change event");

            }

            return 0;

    errno = ENODEV;

因為我的闆子還未完善,是以這裡它認為我的sdcard是一個分區,但無關緊要,原理一樣,就根據分區的代碼跟蹤。:handlePartitionRemoved,由于代碼過多,隻貼出核心代碼:

void DirectVolume::handlePartitionRemoved(const char *devpath, NetlinkEvent *evt) {

 if ((dev_t) MKDEV(major, minor) == mCurrentlyMountedKdev) {

        /*

         * Yikes, our mounted partition is going away!

         */

        snprintf(msg, sizeof(msg), "Volume %s %s bad removal (%d:%d)",

                 getLabel(), getMountpoint(), major, minor);

        SLOGD("DirectVolume:(dev_t) MKDEV(major, minor) == mCurrentlyMountedKdev:%d,msg is :%s.",mCurrentlyMountedKdev,msg);

        mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeBadRemoval,

                                             msg, false);

    if (mVm->cleanupAsec(this, true)) {

            SLOGE("Failed to cleanup ASEC - unmount will probably fail!");

        if (Volume::unmountVol(true, false)) {

            SLOGE("Failed to unmount volume on bad removal (%s)", 

                 strerror(errno));

            // XXX: At this point we're screwed for now

        } else {

            SLOGD("Crisis averted");

 到此,直接調用父類的unmountVol方法,unmountVol會通過setState通知架構狀态改變。代碼太多,隻推薦核心代碼:

int Volume::unmountVol(bool force, bool revert) {

 setState(Volume::State_Unmounting);

 而setState會通過socket将msg消息傳給架構

mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeStateChange,

                                         msg, false); 

小結