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