前言
vold作为管理和控制Android 存储设备的后台进程,已经被无数人分析过了,比较好的有这个:
http://blog.csdn.net/fe421504975/article/details/8240190
http://wiki.jikexueyuan.com/project/deep-android-v1/vold-rild.html
写下今天这篇,主要是为了记录一些自己的感悟
框架
代码分析
init进程启动vold
Android起来后会解析init.rc,init.rc中启动了vold,代码如下
service vold /system/bin/vold
class core
socket vold stream 0660 root mount //①
ioprio be 2
① 表示系统会创建一个“ /dev/socket/vold”的socket文件,用来和上层通信
main函数
一切都是从main函数开始的,直接看main函数,简略如下:
int main() {
VolumeManager *vm;
CommandListener *cl;
NetlinkManager *nm;
//1. 创建VolumeManager的实例,作为大总管管理上下层的消息传递
if (!(vm = VolumeManager::Instance())) {
SLOGE("Unable to create VolumeManager");
exit(1);
};
//2. NetlinkManager用来处理下层的消息
if (!(nm = NetlinkManager::Instance())) {
SLOGE("Unable to create NetlinkManager");
exit(1);
};
//3. 创建CommandListener来监听上层消息
cl = new CommandListener();
vm->setBroadcaster((SocketListener *) cl);
nm->setBroadcaster((SocketListener *) cl);
//4. 根据flash类型解析根目录下的fstab.*文件
//并将文件中的每一个有效行都新建一个DirectVolume来管理
if (process_config(vm)) {
SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno));
}
//5. 建立用于底层通信的socket并处理底层netlink消息
if (nm->start()) {
SLOGE("Unable to start NetlinkManager (%s)", strerror(errno));
exit(1);
}
//6. 向/sys/block的uevent文件写入“add”触发内核上报uevent消息
coldboot("/sys/block");
//7. 一切都准备完毕,可以通过/dev/socket/vold与上层通信了
if (cl->startListener()) {
SLOGE("Unable to start CommandListener (%s)", strerror(errno));
exit(1);
}
//8. 主循环不退出
while(1) {
sleep(1000);
}
SLOGI("Vold exiting");
exit(0);
}
可以看到vold启动很简洁,没有什么难点,接下来分析NetlinkManager、CommandListener和VolumeManager
NetlinkManager
NetlinkManager主要是在start上:
int NetlinkManager::start() {
//1. 创建socket,可以在/proc/net/socket
if ((mSock = socket(PF_NETLINK,
SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {
SLOGE("Unable to create uevent socket: %s", strerror(errno));
return -1;
}
//设置socket相关参数
if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
SLOGE("Unable to set uevent socket SO_RCVBUFFORCE option: %s", strerror(errno));
goto out;
}
if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
goto out;
}
//绑定相关的地址跟socket一样用就好了
if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
SLOGE("Unable to bind uevent socket: %s", strerror(errno));
goto out;
}
//这个用来监听socket上报的消息,并处理消息
mHandler = new NetlinkHandler(mSock);
if (mHandler->start()) {
SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
goto out;
}
return 0;
out:
close(mSock);
return -1;
}
NetlinkHandler的继承关系如下(来自深入理解Android 卷I):
主要知道,socketlistener已经实现了socket的监控方法,最后NetlinkHandler只需要实现具体的处理函数onEvent就行了:
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
VolumeManager *vm = VolumeManager::Instance();
const char *subsys = evt->getSubsystem();
if (!subsys) {
SLOGW("No subsystem found in netlink event");
return;
}
// 这里会比对上传的事件是“block”还是“usb”,然后调用VolumeManager的handle函数
if (!strcmp(subsys, "block")) {
vm->handleBlockEvent(evt);
#ifdef USE_USB_MODE_SWITCH
}else if(!strcmp(subsys, "usb") || !strcmp(subsys, "scsi_device")) {
SLOGW("subsystem found in netlink event");
MiscManager *mm = MiscManager::Instance();
mm->handleEvent(evt);
#endif
}
}
VolumeManager
其实VM的handle函数就是遍历所有之前解析好的DirectVolume,并调用它们的handle函数
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
const char *devpath = evt->findParam("DEVPATH");
/* Lookup a volume to handle this device */
VolumeCollection::iterator it; bool hit = false;
//这个就是之前解析好的DirectVolume
for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
// 调用DirectVolume的处理函数
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 }}
DirectVolume
代码比较长,挑重点看
int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {
const char *dp = evt->findParam("DEVPATH");
//遍历路径
for (it = mPaths->begin(); it != mPaths->end(); ++it) {
if (!strncmp(dp, *it, strlen(*it))) {
int action = evt->getAction();
const char *devtype = evt->findParam("DEVTYPE");
//通过action判断是插入还是拔出还是有变更
if (action == NetlinkEvent::NlActionAdd) {
int major = atoi(evt->findParam("MAJOR"));
int minor = atoi(evt->findParam("MINOR"));
char nodepath[255];
snprintf(nodepath,
sizeof(nodepath), "/dev/block/vold/%d:%d",
major, minor);
//创建dev节点
if (createDeviceNode(nodepath, major, minor)) {
SLOGE("Error making device node '%s' (%s)", nodepath,
strerror(errno));
}
//判断是什么类型,物理分区还是逻辑分区;
//如果sd卡只有一个分区,那么上报disk消息
//如果SD卡有多个分区,先上报disk消息,再上报多个partition消息
if (!strcmp(devtype, "disk")) {
handleDiskAdded(dp, evt);
} else {
handlePartitionAdded(dp, evt);
}
/* Send notification iff disk is ready (ie all partitions found) */
if (getState() == Volume::State_Idle) {
char msg[255];
snprintf(msg, sizeof(msg),
"Volume %s %s disk inserted (%d:%d)", getLabel(),
getFuseMountpoint(), mDiskMajor, mDiskMinor);
//通过广播发送消息,还记得之前提供的commandListener嘛?
//这个广播发送者就是它
mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,
msg, false);
}
} else if (action == NetlinkEvent::NlActionRemove) {
if (!strcmp(devtype, "disk")) {
#ifdef SUPPORTED_MULTI_USB_PARTITIONS
if (!strcmp(getLabel(),USB_DISK_LABEL))
handlePartitionRemoved(dp, evt);
#endif
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;
}
看看handleDiskAdded都做了什么事情
void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) {
mDiskMajor = atoi(evt->findParam("MAJOR"));
mDiskMinor = atoi(evt->findParam("MINOR"));
const char *tmp = evt->findParam("NPARTS");
//分区个数,这里应该是0
if (tmp) {
mDiskNumParts = atoi(tmp);
} else {
SLOGW("Kernel block uevent missing 'NPARTS'");
mDiskNumParts = 1;
}
if (mDiskNumParts == 0) {
setState(Volume::State_Idle);
//通过socket发送消息到JAVA层
snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)",
getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);
mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,msg, false);
} else {
setState(Volume::State_Pending);
}
}
CommandListener
可以看到,CL向上层发送有设备插入的广播。上层接受到广播后,会进行处理,然后再向CL发送挂载或者卸载命令等。与上层所有的交互都通过socket进行。
先看下CommandListener的继承关系(来自深入理解Android 卷I):
可以看到,它也是由socketListener继承而来,我们来看看CommandListener的初始化
CommandListener::CommandListener() :
FrameworkListener("vold") {
//CL模块支持的命令
registerCmd(new DumpCmd());
registerCmd(new VolumeCmd());
registerCmd(new AsecCmd());
registerCmd(new ShareCmd());
registerCmd(new StorageCmd());
registerCmd(new XwarpCmd());}
都是registerCmd,所以说这些CMD一定都有共同的特征,他们都实现了一个runCommand的函数。
registerCmd是在FrameworkListener实现的,他的作用就是把Command保存到一个mCommands的列表中。
在上层来消息的时候,遍历这些Command的runCommand方法。
那CL是怎么发送消息给上层的呢?通过SocketClient的sendMsg方法,就可以跟上层通信了
总结
总得来说vold的代码并不困难,稍加分析就可以理清他的逻辑和思路,这篇文章也是编分析编写,如果有不对的地方,请各位大佬指出