android vold 分析,vold流程分析

前言

框架

933246db6f12

VOLD分析.png

代码分析

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

933246db6f12

图片.png

主要知道,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):

933246db6f12

图片.png

可以看到,它也是由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的代码并不困难,稍加分析就可以理清他的逻辑和思路,这篇文章也是编分析编写,如果有不对的地方,请各位大佬指出

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值