深入Mountservice vold(六) handleDiskRemoved handlePartitionRemoved(and5.1)

今天我们来看看vold的拔走存储设备的两个函数handleDiskRemoved handlePartitionRemoved

在vold中,当拔走sd卡,或者拔走otg的u盘等会调用



DirectVolume::handleBlockEvent 函数里的handleDiskRemoved 和 handlePartitionRemoved函数:

            } else if (action == NetlinkEvent::NlActionRemove) {
                if (!strcmp(devtype, "disk")) {
                    handleDiskRemoved(dp, evt);//去除磁盘
                } else {
                    handlePartitionRemoved(dp, evt);//去除分区
                }
            }

正常流程是先调用handlePartitionRemoved,然后再调用handleDiskRemoved函数

先看handlePartitionRemoved函数

void DirectVolume::handlePartitionRemoved(const char * /*devpath*/,
                                          NetlinkEvent *evt) {
    int major = atoi(evt->findParam("MAJOR"));
    int minor = atoi(evt->findParam("MINOR"));
    char msg[255];
    int state;

    SLOGD("Volume %s %s partition %d:%d removed\n", getLabel(), getMountpoint(), major, minor);

    /*
     * The framework doesn't need to get notified of
     * partition removal unless it's mounted. Otherwise
     * the removal notification will be sent on the Disk
     * itself
     */
    state = getState();
    if (state != Volume::State_Mounted && state != Volume::State_Shared) {
        return;
    }
        
    if ((dev_t) MKDEV(major, minor) == mCurrentlyMountedKdev) {
        /*
         * Yikes, our mounted partition is going away!
         */

        bool providesAsec = (getFlags() & VOL_PROVIDES_ASEC) != 0;
        if (providesAsec && mVm->cleanupAsec(this, true)) {
            SLOGE("Failed to cleanup ASEC - unmount will probably fail!");
        }

        snprintf(msg, sizeof(msg), "Volume %s %s bad removal (%d:%d)",
                 getLabel(), getFuseMountpoint(), major, minor);
        mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeBadRemoval,
                                             msg, false);

        if (Volume::unmountVol(true, false)) {//走unmount流程
            SLOGE("Failed to unmount volume on bad removal (%s)", 
                 strerror(errno));
            // XXX: At this point we're screwed for now
        } else {
            SLOGD("Crisis averted");
        }
    } else if (state == Volume::State_Shared) {//开启大容量存储的时候,已经是unmount了
        /* removed during mass storage */
        snprintf(msg, sizeof(msg), "Volume %s bad removal (%d:%d)",
                 getLabel(), major, minor);
        mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeBadRemoval,
                                             msg, false);

        if (mVm->unshareVolume(getLabel(), "ums")) {//关闭大容量存储
            SLOGE("Failed to unshare volume on bad removal (%s)",
                strerror(errno));
        } else {
            SLOGD("Crisis averted");
        }
    }
}
再看handleDiskRemoved函数

void DirectVolume::handleDiskRemoved(const char * /*devpath*/,
                                     NetlinkEvent *evt) {
    int major = atoi(evt->findParam("MAJOR"));
    int minor = atoi(evt->findParam("MINOR"));
    char msg[255];
    bool enabled;

    if (mVm->shareEnabled(getLabel(), "ums", &enabled) == 0 && enabled) {//如果开启大容量存储,这种情况只有在otg插u盘开启大容量存储的时候。直接到这函数,而不走handlePartitionRemoved,因为有的u盘可能没有分区就不走handlePartitionRemoved了
        mVm->unshareVolume(getLabel(), "ums");
    }

    SLOGD("Volume %s %s disk %d:%d removed\n", getLabel(), getMountpoint(), major, minor);
    snprintf(msg, sizeof(msg), "Volume %s %s disk removed (%d:%d)",
             getLabel(), getFuseMountpoint(), major, minor);
    mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskRemoved,// 发送到MountService
                                             msg, false);
    setState(Volume::State_NoMedia);//改变volume的状态
}

但是原生有问题,有时候otg插U盘,这样直接把调U盘的话,如果有的U盘没有分区,就直接走handleDiskRemoved。这样handleDiskRemoved函数中又没有执行unmount流程,下次再要挂载就会出问题。

所以要修改的话可以这样做,如果没有分区的话,也要走卸载流程

void DirectVolume::handleDiskRemoved(const char * /*devpath*/,
                                     NetlinkEvent *evt) {
    int major = atoi(evt->findParam("MAJOR"));
    int minor = atoi(evt->findParam("MINOR"));
    char msg[255];
    bool enabled;

    if (mVm->shareEnabled(getLabel(), "ums", &enabled) == 0 && enabled) {
        mVm->unshareVolume(getLabel(), "ums");
    }

    SLOGD("Volume %s %s disk %d:%d removed\n", getLabel(), getMountpoint(), major, minor);
    snprintf(msg, sizeof(msg), "Volume %s %s disk removed (%d:%d)",
             getLabel(), getFuseMountpoint(), major, minor);
    mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskRemoved,
                                             msg, false);
    //everytime handleDiskRemoved do an umount action first.
    if (mDiskNumParts == 0) {//新增,没有分区
        SLOGI("handleDiskRemoved: mDiskNumParts is 0 need to do an umount");
        if (mVm->cleanupAsec(this, true)) {
            SLOGE("handleDiskRemoved: Failed to cleanup ASEC - unmount will probably fail!");
        }

        if (Volume::unmountVol(true, false)) {
            SLOGE("handleDiskRemoved: Failed to unmount volume on bad removal (%s)",strerror(errno));
        } else {
            SLOGD("handleDiskRemoved: Crisis averted");
        }
    }
    setState(Volume::State_NoMedia);
}


我们再来看看MountService对这两个函数发给它的消息的处理,在onEvent函数中:

else if (code == VoldResponseCode.VolumeDiskRemoved) {//正常先走badremoval,再走这
                /*
                 * This event gets trumped if we're already in BAD_REMOVAL state
                 */
                if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {//正常流程直接结束了
                    return true;
                }
                /* Send the media unmounted event first */
                if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
                updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);//如果走这是,先不是走的badremoval。比如没有分区的存储设备remove
                sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL);

                if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed");
                updatePublicVolumeState(volume, Environment.MEDIA_REMOVED);
                action = Intent.ACTION_MEDIA_REMOVED;
            } else if (code == VoldResponseCode.VolumeBadRemoval) {//正常流程是先走这
                if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
                /* Send the media unmounted event first */
                updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);//先变成unmounted状态
                sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL);

                if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal");
                updatePublicVolumeState(volume, Environment.MEDIA_BAD_REMOVAL);//改成badremoval
                action = Intent.ACTION_MEDIA_BAD_REMOVAL;
            }



你可能感兴趣的:(深入Mountservice vold(六) handleDiskRemoved handlePartitionRemoved(and5.1))