詳細Mountservice vold(六)handleDiskRemoved handlePartitionRemoved(and 5.1)
7426 ワード
今日は、voldがストレージデバイスを抜いた2つの関数handleDiskRemoved handlePartitionRemovedを見てみましょう.
voldでは、sdカードを抜いたり、otgのuディスクを抜いたりすると呼び出されます
DirectVolume::handleBlockEvent関数のhandleDiskRemovedとhandlePartitionRemoved関数:
通常のプロセスでは、handlePartitionRemovedを呼び出してからhandleDiskRemoved関数を呼び出します.
まずhandlePartitionRemoved関数を見てみましょう
しかし、原生に問題があり、時にはotgがUディスクに挿入され、そのままUディスクを調整すると、あるUディスクにパーティションがなければhandleDiskRemovedに直行します.これによりhandleDiskRemoved関数ではunmountプロセスが実行されず、次回マウントすると問題が発生します.
だから修正するならそうしてもいいし、パーティションがなければアンインストールプロセスも
MountServiceがonEvent関数で2つの関数に送信したメッセージの処理を見てみましょう.
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
", 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
", 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
", 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関数で2つの関数に送信したメッセージの処理を見てみましょう.
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;
}