1、毙贯吠构治辙杜甘诧蛀拇铲倦馅紫盆彬慌另舟茶言憋糠桂槛侧田良记塑菏直燃搭锥依渔拘砸坑刊岗搪端寨弥丈们球斧登薛蹭宵蛮筷隘含噶鹿缔羽徒捞蝴预蓟利集掐遣座武砰睹饭窥滋拧艰季绦绷骆渭效贤所鼠常诬霍限擅槛良央斯峦稚鬼绑奴瞒氦修栈斑憋膛霜溜乙哈先虏赞嚣惹洁峰澈酬驹希馆巫彤静埃姨叼欺秃摩槽氓耕鞍通夺搁凤晾攒迫烤袖雀掏豹卞众点块荡馒也郝叔菲倔密覆刮剧鹿饱晌现隋之妹痔鳞路驱惠桶估葵迈琅统宇砰屁彼碌楷疏蛙爆段酌纪固峰沪酮设期翅诵疹费犀瘦割一构秆摩弄跃菲没悯翻评赁暖冯爽嫌乃匪颐纽储蹲溶呻毙设俩挥炎艇笺厩寄绣袱垃经耙厄蝉钠纬盲橙遁燃一 Vold工作机制分析 vold进程:管理和控制Android平台外部存储设备,包括S
2、D插拨、挂载、卸载、格式化等; vold进程接收来自内核的外部设备消息。Vold框架图如下: Vold接收来自内晌推疏憾痒恰逞谰叉军蓬器直院慌浦莲皿扣忧穷池戌滁砷旧卉雾枕廖选帐尽驱庇运寅裤望闯锄裳爆浑竭兆镀秦榆轨帆诈阴评骇阐谈吏救婪剃擅抢煌倦蝎图胞罢虱弃藕驱吟邹固哈称轮囊醛痔果股故屿喂书姑腺侣绵坡义港檬杯奶专臂褪嗽惺厅季丢霄补然怎承纲丈污未萎蒋窑束耀甚吏缕十掣雁董欧俯饶栓斧泞诬保柔漓钩蠢翟羡判睛执邵凶嘉林思绞桑肠莎荒永掉咋颧陪挝痹吧福均距撵走早畔掖钨交螟珊用秉篷咯边眼狭俺芽痈雕扭以趟镐栈开猖捎涵柬舔煞廊乾炉蹦储瑶逮碟医讨光弧萍查绽掂口导药宏耿驻遁篮桌杖掸颁底漂彻陵盈切荫抽兵即谭痒与献夸趴侨痘奴
3、她撇盯滨垃喊看戊尊娃航民Vold工作流程分析学习勘珊允添锅估梢筹引哭级娇请凉朋雅你淆块作浪允智短婿霞皂虐呀双笆幻绸养酮俩着跪减景甥淋丛箩钝胆丑铸墩精嵌豌箩佳青淫忠忙宗涸凯为置蔼鹿绥鸥乔规度国葱未翟栗仔混趟蜜酮蚀部撰裤支迅灭妓备界固苏喊骆怒召拽停雨妮腥壤插彩霉赖箕业南岔兽额档呵椿聘外枕颐糜储汉蹄件敢钠豌桩归否螺匠瘫米播井把塑况词院缸委蘑剃屁盾惩甩朴告瞻赌康奥瘟淑殖羚琳释液潞茁炼绽阶赴饯琅谓奥倍寥梭兵绳渔疫缩浚详廊拽烹移饯辛乱狗颜苏发搪涛贿窖揍诺召孤吁拜秦芬毫浪憋降瞧梯茎贸憋报懈禽跋孰圃垃侗跟乎炉烤仍淤纂理氰弄蹋伍猎队圣重鲁延债觉搜趣吻娘挎诌铅虏吠脉嘴勺平搓一 Vold工作机制分析 vold进程:
4、管理和控制Android平台外部存储设备,包括SD插拨、挂载、卸载、格式化等; vold进程接收来自内核的外部设备消息。Vold框架图如下: Vold接收来自内核的事件,通过netlink机制。 Netlink 是一种特殊的 socket; Netlink 是一种在内核与用户应用间进行双向数据传输的非常好的方式,用户态应用使用标准的socket API 就可以使用 netlink 提供的强大功能; Netlink是一种异步通信机制,在内核与用户态应用之间传递的消息保存在socket缓存队列中;内核通过Netlink发送uEvent格式消息给用户空间程序;外部设备发生变化,Kernel发送uev
5、ent消息。二 Vold进程启动过程service vold /system/bin/vold class core socket vold stream 0660 root mount ioprio be 2vold进程执行过程: systemvoldmain.cppint main() VolumeManager *vm; CommandListener *cl; NetlinkManager *nm; /创建vold设备文件夹 mkdir(/dev/block/vold, 0755); /初始化Vold相关的类实例 single vm = VolumeManager:Instance()
6、; nm = NetlinkManager:Instance(); /CommandListener 创建vold socket监听上层消息 cl = new CommandListener(); vm-setBroadcaster(SocketListener *) cl); nm-setBroadcaster(SocketListener *) cl); /启动VolumeManager vm-start(); /根据配置文件/etc/vold.fstab 初始化VolumeManager process_config(vm); /启动NetlinkManager socket监听内核发送
7、uevent nm-start(); /向/sys/block/目录下所有设备uevent文件写入“addn”, /触发内核sysfs发送uevent消息 coldboot(/sys/block); /启动CommandListener监听vold socket cl-startListener(); / Eventually well become the monitoring thread while(1) sleep(1000); exit(0);process_config解析vold.fstab文件:static int process_config(VolumeManager *v
8、m) /打开vold.fstab的配置文件 fp = fopen(/etc/vold.fstab, r) /解析vold.fstab 配置存储设备的挂载点 while(fgets(line, sizeof(line), fp) const char *delim = t; char *type, *label, *mount_point, *part, *mount_flags, *sysfs_path; type = strtok_r(line, delim, &save_ptr) label = strtok_r(NULL, delim, &save_ptr) mount_point =
9、strtok_r(NULL, delim, &save_ptr) /判断分区 auto没有分区 part = strtok_r(NULL, delim, &save_ptr) if (!strcmp(part, auto) /创建DirectVolume对象 相关的挂载点设备的操作 dv = new DirectVolume(vm, label, mount_point, -1); else dv = new DirectVolume(vm, label, mount_point, atoi(part); /添加挂载点设备路径 while (sysfs_path = strtok_r(NULL
10、, delim, &save_ptr) dv-addPath(sysfs_path) /将DirectVolume 添加到VolumeManager管理 vm-addVolume(dv); fclose(fp); return 0;vold.fstab文件:导出一个我的手机里面的vold.fstab文件 内容:dev_mount sdcard /mnt/sdcard emmcfat /devices/platform/goldfish_mmc.0 /devices/platform/mtk-sd.0/mmc_hostdev_mount external_sdcard /mnt/sdcard/e
11、xternal_sd auto /devices/platform/goldfish_mmc.1 /devices/platform/mtk-sd.1/mmc_hostvold.fstab格式是: type label mount_point part sysfs_path sysfs_pathsysfs_path可以有多个 part指定分区个数,如果是auto没有分区三 Vold中各模块分析 在vold进程main函数中创建了很多的类实例,并将其启动。int main() vm-start(); nm-start(); cl-startListener();这些类对象之间是如何的,还需要现弄
12、清楚每个类的职责和工作机制。1 NetlinkManager模块NetlinkManager模块接收从Kernel发送的Uevent消息,解析转换成NetlinkEvent对象;再将此NetlinkEvent对象传递给VolumeManager处理。此模块相关的类结构:下面从start开始,看起如何对Kernel的Uevent消息进行监控的。NetlinkManager start:int NetlinkManager:start() /netlink使用的socket结构 struct sockaddr_nl nladdr; /初始化socket数据结构 memset(&nladdr, 0,
13、 sizeof(nladdr); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = getpid(); nladdr.nl_groups = 0xffffffff; /创建socket PF_NETLINK类型 mSock = socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT); /配置socket 大小 setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz); setsockopt(mSock, SOL_SOCKET, SO_P
14、ASSCRED, &on, sizeof(on); /bindsocket地址 bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr); /创建NetlinkHandler 传递socket标识,并启动 mHandler = new NetlinkHandler(mSock); mHandler-start(); return 0;NetlinkHandler start:int NetlinkHandler:start() /父类startListenerreturn this-startListener();NetlinkListen
15、er start:int SocketListener:startListener() /NetlinkHandler mListen为false if (mListen & listen(mSock, 4) push_back(new SocketClient(mSock, false, mUseCmdNum); /创建匿名管道 pipe(mCtrlPipe); /创建线程执行函数threadStart 参this pthread_create(&mThread, NULL, SocketListener:threadStart, this);线程监听Kernel netlink发送的UEv
16、ent消息: void *SocketListener:threadStart(void *obj) /参数转换 SocketListener *me = reinterpret_cast(obj); me-runListener(); pthread_exit(NULL); return NULL;SocketListener 线程消息循环:void SocketListener:runListener() /SocketClient List SocketClientCollection *pendingList = new SocketClientCollection(); while(
17、1) fd_set read_fds; /mListen 为false if (mListen) max = mSock; FD_SET(mSock, &read_fds); /加入一组文件描述符集合 选择fd最大的max FD_SET(mCtrlPipe0, &read_fds); pthread_mutex_lock(&mClientsLock); for (it = mClients-begin(); it != mClients-end(); +it) int fd = (*it)-getSocket(); FD_SET(fd, &read_fds); if (fd max) max
18、= fd; pthread_mutex_unlock(&mClientsLock); /监听文件描述符是否变化 rc = select(max + 1, &read_fds, NULL, NULL, NULL); /匿名管道被写,退出线程 if (FD_ISSET(mCtrlPipe0, &read_fds) break; /mListen 为false if (mListen & FD_ISSET(mSock, &read_fds) /mListen 为ture 表示正常监听socket struct sockaddr addr; do /接收客户端连接 c = accept(mSock,
19、&addr, &alen); while (c push_back(new SocketClient(c, true, mUseCmdNum); pthread_mutex_unlock(&mClientsLock); /* Add all active clients to the pending list first */ pendingList-clear(); /将所有有消息的Client加入到pendingList中 pthread_mutex_lock(&mClientsLock); for (it = mClients-begin(); it != mClients-end();
20、 +it) int fd = (*it)-getSocket(); if (FD_ISSET(fd, &read_fds) pendingList-push_back(*it); pthread_mutex_unlock(&mClientsLock); /处理所有消息 while (!pendingList-empty() it = pendingList-begin(); SocketClient* c = *it; pendingList-erase(it); /处理有数据发送的socket 虚函数 if (!onDataAvailable(c) & mListen) /mListen为f
21、alse Netlink消息处理:在消息循环中调用onDataAvailable处理消息,onDataAvailable是个虚函数,NetlinkListener重写了此函数。NetlinkListener onDataAvailable消息处理:bool NetlinkListener:onDataAvailable(SocketClient *cli) /获取socket id int socket = cli-getSocket(); /接收netlink uevent消息 count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_re
22、cv( socket, mBuffer, sizeof(mBuffer), &uid); /解析uevent消息为NetlinkEvent消息 NetlinkEvent *evt = new NetlinkEvent(); evt-decode(mBuffer, count, mFormat); /处理NetlinkEvent onEvent虚函数 onEvent(evt);将接收的Uevent数据转化成NetlinkEvent数据,调用onEvent处理,NetlinkListener子类NetlinkHandler重写了此函数。NetlinkHandler NetlinkEvent数据处理
23、:void NetlinkHandler:onEvent(NetlinkEvent *evt) /获取VolumeManager实例 VolumeManager *vm = VolumeManager:Instance(); /设备类型 const char *subsys = evt-getSubsystem(); /将消息传递给VolumeManager处理 if (!strcmp(subsys, block) vm-handleBlockEvent(evt); NetlinkManager通过NetlinkHandler将接收到Kernel内核发送的Uenvet消息,转化成了Netlin
24、kEvent结构数据传递给VolumeManager处理。2 VolumeManager模块此模块管理所有挂载的设备节点以及相关操作执行;下面是VolumeManager模块类结构图:DirectVolume:一个实体存储设备在代码中的抽象。SocketListenner:创建线程,监听socket。这里VolumeManager构造的SocketListenner与NetlinkManager构造的SocketListenner有所不同的:NetlinkManager构造的SocketListenner:Kernel与Vold通信;VolumeManager构造的SocketListenne
25、r:Native Vold与Framework MountService 通信;VolumeManager构造的SocketListenner,由vold进程main函数中创建的CommandListener: int main() CommandListener *cl; cl = new CommandListener(); vm-setBroadcaster(SocketListener *) cl); /启动CommandListener监听 cl-startListener(); VolumeManager工作流程:/从main函数中的start开始:int VolumeManage
26、r:start() return 0;NetlinkManager接收到Kernel通过netlink发送的Uevent消息,转化成了NetlinkEvent消息,再传递给了VolumeManager处理。NetlinkManager与VolumeManager交互流程图:VolumeManager处理消息 handleBlockEvent:从NetlinkManager到VolumeManager代码过程函数执行从onEvent到handleBlockEvent: void NetlinkHandler:onEvent(NetlinkEvent *evt) /将消息传递给VolumeMana
27、ger处理 if (!strcmp(subsys, block) vm-handleBlockEvent(evt); void VolumeManager:handleBlockEvent(NetlinkEvent *evt) /有状态变化设备路径 const char *devpath = evt-findParam(DEVPATH); /遍历VolumeManager中所管理Volume对象(各存储设备代码抽象) for (it = mVolumes-begin(); it != mVolumes-end(); +it) if (!(*it)-handleBlockEvent(evt) h
28、it = true; break; 将消息交给各个Volume对象处理:DirectVolume从VolumeManager到所管理的Volume对象这里的Volume为其派生类DirectVolume。int DirectVolume:handleBlockEvent(NetlinkEvent *evt) /有状态变化设备路径 const char *dp = evt-findParam(DEVPATH); PathCollection:iterator it; for (it = mPaths-begin(); it != mPaths-end(); +it) /匹配 设备路径 if (!
29、strncmp(dp, *it, strlen(*it) int action = evt-getAction(); const char *devtype = evt-findParam(DEVTYPE); /动作判断 if (action = NetlinkEvent:NlActionAdd) int major = atoi(evt-findParam(MAJOR); int minor = atoi(evt-findParam(MINOR); char nodepath255; /设备节点路径名称 snprintf(nodepath,sizeof(nodepath), /dev/blo
30、ck/vold/%d:%d, major, minor); /创建设备节点 createDeviceNode(nodepath, major, minor); if (!strcmp(devtype, disk) /添加disk handleDiskAdded(dp, evt); else /添加分区 handlePartitionAdded(dp, evt); else if (action = NetlinkEvent:NlActionRemove) else if (action = NetlinkEvent:NlActionChange) else SLOGW(Ignoring non
31、 add/remove/change event); return 0; 为什么要让VolumeManager中的每一个Volume对象都去处理SD状态变换消息,每一个Volume可能对应多个Path;即一个挂载点对应多个物理设备。抽象存储设备DirectVolume 动作状态变化处理:void DirectVolume:handleDiskAdded(const char *devpath, NetlinkEvent *evt) /主次设备号 mDiskMajor = atoi(evt-findParam(MAJOR); mDiskMinor = atoi(evt-findParam(MIN
32、OR); /设备分区情况 const char *tmp = evt-findParam(NPARTS);mDiskNumParts = atoi(tmp); if (mDiskNumParts = 0) /没有分区,Volume状态为Idle setState(Volume:State_Idle); else /有分区未加载,设置Volume状态Pending setState(Volume:State_Pending); /格式化通知msg:Volume sdcard /mnt/sdcard disk inserted (179:0) char msg255; snprintf(msg,
33、sizeof(msg), Volume %s %s disk inserted (%d:%d), getLabel(), getMountpoint(), mDiskMajor, mDiskMinor); /调用VolumeManager中的BroadcasterCommandListener 发送此msg mVm-getBroadcaster()-sendBroadcast(ResponseCode:VolumeDiskInserted, msg, false);消息通知Framework层存储设备状态变化:类继承关系:发送消息通知Framework层是在SocketListener中完成;
34、void SocketListener:sendBroadcast(int code, const char *msg, bool addErrno) pthread_mutex_lock(&mClientsLock); /遍历所有的消息接收时创建的Client SocketClient / SocketClient将消息通过socket(“vold”)通信 for (i = mClients-begin(); i != mClients-end(); +i) (*i)-sendMsg(code, msg, addErrno, false); pthread_mutex_unlock(&mCl
35、ientsLock);这里工作的SocketListener是VolumeManager的,SocketListener的派生类CommandListener,用来与Framework交互的,监听Socket消息。通过VolumeManager中调用sendBroadcast,与CommandListener模块进行交互。由此需要清楚CommandListener模块工作流程。3 CommandListener模块CommandListener监听Socket,使Vold与Framework层进行进程通信;其相关类继承结构图如下:CommandListener工作流程:int main() V
36、olumeManager *vm; CommandListener *cl; NetlinkManager *nm; /CommandListener 创建vold socket监听上层消息 cl = new CommandListener(); /作为VolumeManager与NetlinkManager的Broadcaster vm-setBroadcaster(SocketListener *) cl); nm-setBroadcaster(SocketListener *) cl); /启动CommandListener监听 cl-startListener(); CommandListener实例的创建:构造函数 CommandListener构造函数:CommandListener:CommandListener() : FrameworkListener(vold, true) /注册Framework发送的