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<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);

下一篇文章继续。。。

你可能感兴趣的:(android,File,iterator,存储,action,磁盘)