作者: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<Volume *> 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);
下一篇文章继续。。。