Android磁盘管理-之vold源码分析(4)

作者:gzshun. 原创作品,转载请标明出处!

上篇文章分析到了NetlinkHandler类中的onEvent函数,该函数由NetlinkListener::onDataAvailable函数调用,当SocketListener类监听到内核的uevent事件,调用该函数,之后的事情交给onEvent来负责。


file:system/vold/NetlinkHandler.cpp
现在来说onEvent函数,在vold中,磁盘的热插拔事件都是通过上述那些间接的过程来调用到
该函数,该函数再调用vold中的处理事件的函数,这样vold就能得到最新的磁盘热插拔事件;

void NetlinkHandler::onEvent(NetlinkEvent *evt) { VolumeManager *vm = VolumeManager::Instance(); const char *subsys = evt->getSubsystem(); if (!subsys) { SLOGW("No subsystem found in netlink event"); return; } if (!strcmp(subsys, "block")) { vm->handleBlockEvent(evt); } else if (!strcmp(subsys, "switch")) { vm->handleSwitchEvent(evt); } else if (!strcmp(subsys, "battery")) { } else if (!strcmp(subsys, "power_supply")) { } }file:system/vold/VolumeManager.cpp
vm->handleSwitchEvent(evt)函数涉及的比较少,先来分析;
该函数是用来处理大容量存储设备,也就是otg功能,NetlinkEvent类提供的findParam函数
可以获取到该事件的具体信息,比如设备路径,设备名称,状态,分区数量等等。。
如果判断是“online”状态,那么就向framework发送状态消息。使用notifyUmsConnected函数
进行广播。

void VolumeManager::handleSwitchEvent(NetlinkEvent *evt) { const char *devpath = evt->findParam("DEVPATH"); const char *name = evt->findParam("SWITCH_NAME"); const char *state = evt->findParam("SWITCH_STATE"); if (!name || !state) { SLOGW("Switch %s event missing name/state info", devpath); return; } if (!strcmp(name, "usb_mass_storage")) { if (!strcmp(state, "online")) { notifyUmsConnected(true); } else { notifyUmsConnected(false); } } else { SLOGW("Ignoring unknown switch '%s'", name); } }
notifyUmsConnected函数将otg的状态发送给framework,
命令为:Share method ums now available/unavailable;
getBroadcaster()->sendBroadcast()广播函数,这在main函数分析中就涉及到了,
源码:
cl = new CommandListener();
vm->setBroadcaster((SocketListener *) cl);
nm->setBroadcaster((SocketListener *) cl);
将CommandListener对象强制转换成SocketListener类型,这样cl对象就能够调用SocketListener
类的setBroadcaster广播函数;
getBroadcaster()的源码:
SocketListener *getBroadcaster() { return mBroadcaster; }
直接将刚才被强制转换成SocketListener类型返回,相当于如下:
(SocketListener *)cl->sendBroadcast(xxx);
void VolumeManager::notifyUmsConnected(bool connected) { char msg[255]; if (connected) { mUsbMassStorageConnected = true; } else { mUsbMassStorageConnected = false; } snprintf(msg, sizeof(msg), "Share method ums now %s", (connected ? "available" : "unavailable")); getBroadcaster()->sendBroadcast(ResponseCode::ShareAvailabilityChange, msg, false); }
file:system/vold/ResponseCode.cpp
该类没做什么事,也就是提供一些出错标志,下面将写出出错原因;
这些标志都会在不同的操作(命令)反馈不同的值。

class ResponseCode { public: // 100 series - Requestion action was initiated; expect another reply // before proceeding with a new command. static const int ActionInitiated = 100; static const int VolumeListResult = 110; static const int AsecListResult = 111; static const int StorageUsersListResult = 112; // 200 series - Requested action has been successfully completed static const int CommandOkay = 200; static const int ShareStatusResult = 210; static const int AsecPathResult = 211; static const int ShareEnabledResult = 212; static const int XwarpStatusResult = 213; // 400 series - The command was accepted but the requested action // did not take place.//这几个标志有点重复性,其实vold里面也没有这几个标志。 static const int OperationFailed = 400; static const int OpFailedNoMedia = 401; static const int OpFailedMediaBlank = 402; static const int OpFailedMediaCorrupt = 403; static const int OpFailedVolNotMounted = 404; static const int OpFailedStorageBusy = 405; static const int OpFailedStorageNotFound = 406; // 500 series - The command was not accepted and the requested // action did not take place. static const int CommandSyntaxError = 500;// static const int CommandParameterError = 501;// // 600 series - Unsolicited broadcasts static const int UnsolicitedInformational = 600; static const int VolumeStateChange = 605; static const int VolumeMountFailedBlank = 610; static const int VolumeMountFailedDamaged = 611; static const int VolumeMountFailedNoMedia = 612; static const int ShareAvailabilityChange = 620; static const int VolumeDiskInserted = 630; static const int VolumeDiskRemoved = 631; static const int VolumeBadRemoval = 632; static int convertFromErrno(); };
file:system/vold/VolumeManager.cpp
该函数用来捕获磁盘的热插拔事件信息。
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) { const char *devpath = evt->findParam("DEVPATH"); VolumeCollection::iterator it; bool hit = false; /********************************************************************************** **mVolumes是一个存放volume*的容器,类型如下: **typedef android::List VolumeCollection; **mVolumes是在main函数中添加进磁盘的,在mian函数中,使用process_config函数分析 **/etc/vold.fstab配置文件,然后将磁盘的信息添加进该容器,以便后续的操作。 **********************************************************************************/ 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) { #ifdef NETLINK_DEBUG SLOGW("No volumes handled block event for '%s'", devpath); #endif } }
这里使用(*it)调用handleBlockEvent函数,可以看出handleBlockEvent在Volume类对象实现,
源码在system/vold/Volume.cpp
可以发现,该函数并没有做什么事情,其实handleBlockEvent函数在Volume的子类DirectVolume
中重写了。

int Volume::handleBlockEvent(NetlinkEvent *evt) { errno = ENOSYS; return -1; }
file:system/vold/DirectVolume.cpp
这函数是处理热插拔事件最重要的函数,Volume若要操作磁盘,肯定先要从这个函数获取到
磁盘事件和信息。

int DirectVolume::handleBlockEvent(NetlinkEvent *evt) { const char *dp = evt->findParam("DEVPATH"); PathCollection::iterator it; for (it = mPaths->begin(); it != mPaths->end(); ++it) { size_t len = strlen(*it); if (!strncmp(dp, *it, len) && (dp[len] == '\0' || dp[len] == '/')) { /* We can handle this disk */ int action = evt->getAction(); const char *devtype = evt->findParam("DEVTYPE"); /********************************************************************************** **NetlinkEvent提供4个uevent状态,代码: **const int NetlinkEvent::NlActionUnknown = 0; const int NetlinkEvent::NlActionAdd = 1; //增加硬盘或分区的事件 const int NetlinkEvent::NlActionRemove = 2;//移除硬盘或分区的事件 const int NetlinkEvent::NlActionChange = 3;//改变硬盘或分区的事件 **这里的事件是增加存储设备 **********************************************************************************/ if (action == NetlinkEvent::NlActionAdd) { /*从这里获取到主次设备号*/ int major = atoi(evt->findParam("MAJOR")); int minor = atoi(evt->findParam("MINOR")); char nodepath[255]; /********************************************************************************** **之前有提到过,vold在/dev/block/vold创建了相应的设备节点,诸如8:0形式的节点,这里 **就是创建节点的位置,createDeviceNode函数。 **********************************************************************************/ 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) { if (!strcmp(devtype, "disk")) { handleDiskRemoved(dp, evt); } else { handlePartitionRemoved(dp, evt); } } /*改变存储设备*/ else if (action == NetlinkEvent::NlActionChange) { if (!strcmp(devtype, "disk")) { handleDiskChanged(dp, evt); } else { handlePartitionChanged(dp, evt); } } else { SLOGW("Ignoring non add/remove/change event"); } return 0; } } errno = ENODEV; return -1; }
该函数主要对存储设备或分区处理,每个存储设备或分区都有增加、删除和改变的事件,下一篇文章介绍
每个不同事件和函数的处理,有以下6个函数:

void handleDiskAdded(const char *devpath, NetlinkEvent *evt); void handleDiskRemoved(const char *devpath, NetlinkEvent *evt); void handleDiskChanged(const char *devpath, NetlinkEvent *evt); void handlePartitionAdded(const char *devpath, NetlinkEvent *evt); void handlePartitionRemoved(const char *devpath, NetlinkEvent *evt); void handlePartitionChanged(const char *devpath, NetlinkEvent *evt);
下一篇文章继续。。。

你可能感兴趣的:(Android磁盘管理-之vold源码分析(4))