Android 磁盘管理 (3)

来源:互联网 发布:今天双11网络怎么了 编辑:程序博客网 时间:2024/06/08 02:10
上篇文章分析到了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);

下一篇文章继续。

原创粉丝点击