今天我们来看看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; }