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

下一篇文章继续。。。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是一个基于Matlab实现Vold-Kalman滤波器的代码示例: ``` function [xhat,Phat] = vold_kalman(y,u,x0,P0,Q,R,dt) % Vold-Kalman滤波器 % 输入: % y - 观测数据 % u - 控制数据 % x0 - 初始状态 % P0 - 初始协方差矩阵 % Q - 过程噪声协方差矩阵 % R - 观测噪声协方差矩阵 % dt - 时间步长 % 输出: % xhat - 状态估计值 % Phat - 协方差估计矩阵 % 系统模型 f = @(x, u) [x(1) + u(1)*cos(x(3))*dt; x(2) + u(1)*sin(x(3))*dt; x(3) + u(2)*dt]; h = @(x) [atan2(x(2),x(1)); sqrt(x(1)^2 + x(2)^2)]; % 初始化滤波器 xhat = x0; Phat = P0; % 迭代 for i = 1:length(y) % 预测 uhat = u(:,i); [xhat, Fx, Fu, Q] = ekf_predict(f, xhat, uhat, Phat, Q, dt); % 更新 yhat = y(:,i); [xhat, Phat, H, R] = ekf_update(h, xhat, yhat, Phat, R); % 存储结果 X(:,i) = xhat; P_all(:,:,i) = Phat; end end function [xhat,Fx,Fu,Q] = ekf_predict(f,x,u,P,Q,dt) % 扩展卡尔曼滤波器预测 % 输入: % f - 状态方程 % x - 状态估计值 % u - 控制输入 % P - 协方差估计矩阵 % Q - 过程噪声协方差矩阵 % dt - 时间步长 % 输出: % xhat - 预测状态估计值 % Fx - 状态转移矩阵 % Fu - 控制输入矩阵 % Q - 更新后的过程噪声协方差矩阵 % 计算状态转移矩阵和控制输入矩阵 [Fx,Fu] = jacobian(f,x,u); % 预测状态估计值和协方差矩阵 xhat = f(x,u); P = Fx*P*Fx' + Fu*Q*Fu'; % 更新过程噪声协方差矩阵 Q = diag([0.01,0.01,0.01]); % TODO: 根据实际问题调整 end function [xhat,P,H,R] = ekf_update(h,x,y,P,R) % 扩展卡尔曼滤波器更新 % 输入: % h - 观测方程 % x - 状态估计值 % y - 观测值 % P - 协方差估计矩阵 % R - 观测噪声协方差矩阵 % 输出: % xhat - 更新后的状态估计值 % P - 更新后的协方差估计矩阵 % H - 观测矩阵 % R - 更新后的观测噪声协方差矩阵 % 计算观测矩阵 H = jacobian(h,x); % 计算观测噪声协方差矩阵 R = diag([0.1,0.1]); % TODO: 根据实际问题调整 % 计算卡尔曼增益 K = P*H'/(H*P*H' + R); % 更新状态估计值和协方差矩阵 xhat = x + K*(y - h(x)); P = (eye(size(P)) - K*H)*P; end function [F,J] = jacobian(f,x,u) % 计算函数f(x,u)关于x和u的雅可比矩阵 % 输入: % f - 目标函数 % x - 自变量x % u - 自变量u % 输出: % F - 状态转移矩阵 % J - 控制输入矩阵 % 计算状态转移矩阵 n = length(x); Fx = zeros(n,n); for i = 1:n Fx(:,i) = gradient(f(x,u),x(i)); end F = eye(n) + Fx; % 计算控制输入矩阵 if nargin > 2 m = length(u); Fu = zeros(n,m); for i = 1:m Fu(:,i) = gradient(f(x,u),u(i)); end J = Fu; end end ``` 这个代码示例中实现了Vold-Kalman滤波器的预测和更新步骤,同时也使用了扩展卡尔曼滤波器(EKF)来处理非线性系统。需要根据具体问题调整系统模型和协方差矩阵,以获得更好的滤波效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值