上一篇講到通過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);