




已阅读5页,还剩22页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Android - Vold机制简要分析Vold是用于管理和控制Android外部存储介质的后台进程,这里说的管控,主要包括SDK的插拔、挂载/卸载和格式化等;它是Android平台外部存储系统的管控枢纽。Vold的整个控制模块主要由三个类模块构成:NetlinkManager、VolumeManager和CommandListener,它们的功能划分大概是:NetlinkManager:用于从kernel中获取SD卡插拔的Uevnet消息VolumeManager:管理模块,对NetlinkManager转发的消息做一些处理,并通过CommandListener发送给framework(MountService.java);接着framework会通过套接字下发命令,指引VolumeManager对存储设备做下一步的操作,如挂载/卸载等CommandListener:通过socket,实现MountService.java与Vold之间的消息交换NetLink是Linux下用户进程和kernel进行信息交互的一种机制,借助这种机制,用户进程(如Vold/Netd)可以接收来自kernel的一些消息,同时也可以向kernel发送一些控制命令。NetlinkManager就是基于此设计的。Uevent也跟Linux系统有关,它与Linux 的设备文件系统有一定关系;这里,我们可以简单的认为,Uevent就是一个字符串,它描述了外部存储设备插入/拔出、挂载/卸载的状态信息。Vold通过Netlink机制,可以得到这些信息,并进行外部存储设备的管理、控制。由上述介绍,我们可以得到如下的Vold框架图描述:有了Vold的架构描述,接下来就开始分析Vold进程的整体流程及实现了。一、Vold进程的声明与创建Vold进程的声明与创建过程跟zygote一样,在init.rc中声明,在init进程创建:java view plain copy 在CODE上查看代码片派生到我的代码片service vold /system/bin/vold -blkid_context=u:r:blkid:s0 -blkid_untrusted_context=u:r:blkid_untrusted:s0 -fsck_context=u:r:fsck:s0 -fsck_untrusted_context=u:r:fsck_untrusted:s0 class core socket vold stream 0660 root mount socket cryptd stream 0660 root mount ioprio be 2 在创建Vold进程时,会为它创建两个socket,用于与framework进行信息交互。其他的细节,参考之前zygote进程创建的介绍。二、进入Vold主程序Vold的主程序在/system/vold目录中,直接看main.cpp:main()函数:cpp view plain copy 在CODE上查看代码片派生到我的代码片int main(int argc, char* argv) setenv(ANDROID_LOG_TAGS, *:v, 1); android:base:InitLogging(argv, android:base:LogdLogger(android:base:SYSTEM); LOG(INFO) Vold 3.0 (the awakening) firing up; LOG(VERBOSE) Detected support for: (android:vold:IsFilesystemSupported(ext4) ? ext4 : ) (android:vold:IsFilesystemSupported(f2fs) ? f2fs : ) (android:vold:IsFilesystemSupported(vfat) ? vfat : ); VolumeManager *vm; CommandListener *cl; CryptCommandListener *ccl; NetlinkManager *nm; parse_args(argc, argv); sehandle = selinux_android_file_context_handle(); if (sehandle) selinux_android_set_sehandle(sehandle); / Quickly throw a CLOEXEC on the socket we just inherited from init fcntl(android_get_control_socket(vold), F_SETFD, FD_CLOEXEC);/拿到init进程创建的名为vold的socket句柄,并为它设置FD_CLOEXEC标志位 fcntl(android_get_control_socket(cryptd), F_SETFD, FD_CLOEXEC);/同上 mkdir(/dev/block/vold, 0755);/创建/dev/block/vold目录,存放所有subdisk和sdcard的挂载点信息 /* For when cryptfs checks and mounts an encrypted filesystem */ klog_set_level(6); /* Create our singleton managers */ /1、创建VolumeManager if (!(vm = VolumeManager:Instance() LOG(ERROR) Unable to create VolumeManager; exit(1); /2、创建NetlinkManager if (!(nm = NetlinkManager:Instance() LOG(ERROR) setDebug(true); /3、创建CommandListener、CryptCommandListener cl = new CommandListener(); ccl = new CryptCommandListener(); vm-setBroadcaster(SocketListener *) cl); nm-setBroadcaster(SocketListener *) cl); /4、启动VolumeManager if (vm-start() PLOG(ERROR) Unable to start VolumeManager; exit(1); if (process_config(vm) PLOG(ERROR) start() PLOG(ERROR) startListener() PLOG(ERROR) startListener() PLOG(ERROR) Unable to start CryptCommandListener; exit(1); / Eventually well become the monitoring thread while(1) sleep(1000); LOG(ERROR) setBroadcaster(SocketListener *) cl)nm-start()现按步骤进行分析。1、NetlinkManager:Instance():cpp view plain copy 在CODE上查看代码片派生到我的代码片NetlinkManager *NetlinkManager:Instance() if (!sInstance) sInstance = new NetlinkManager(); return sInstance; NetlinkManager:NetlinkManager() mBroadcaster = NULL; /type:SocketListener*,用来进行socket通信 这里使用了单例模式来构建NetlinkManager对象,构造函数中只是简单地初始化了成员变量。2、NetlinkManager:setBroadcaster():cpp view plain copy 在CODE上查看代码片派生到我的代码片cl = new CommandListener(); nm-setBroadcaster(SocketListener *) cl); void setBroadcaster(SocketListener *sl) mBroadcaster = sl; setBroadcaster()函数也很简单,为mBroadcast进行赋值。3、NetlinkManager:start():cpp view plain copy 在CODE上查看代码片派生到我的代码片int NetlinkManager:start() struct sockaddr_nl nladdr; int sz = 64 * 1024; int on = 1; memset(&nladdr, 0, sizeof(nladdr); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = getpid(); nladdr.nl_groups = 0xffffffff; /创建地址族为PF_NETLINK的socket,与Kernel进行通信;也可以为AF_NETLINK.参照Linux Netlink机制资料 if (mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT) 0) SLOGE(Unable to create uevent socket: %s, strerror(errno); return -1; /设置套接字 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; /为套接字绑定地址 if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr) start() /startListener通过父类方法,在mSock上监听连接请求 SLOGE(Unable to start NetlinkHandler: %s, strerror(errno); goto out; return 0; out: close(mSock); return -1; start()方法中创建了一个句柄值为mSock的套接字,用来和kernel通信;而实际具体的socket信息交互是由NetlinkHandler处理的。NetlinkHandler的实现有一套继承机制,其实际继承关系如图所示:按照继承关系,分析它的构建过程:cpp view plain copy 在CODE上查看代码片派生到我的代码片mHandler = new NetlinkHandler(mSock); NetlinkHandler:NetlinkHandler(int listenerSocket) : NetlinkListener(listenerSocket) cpp view plain copy 在CODE上查看代码片派生到我的代码片/* temporary version until we can get Motorola to update their * ril.so. Their prebuilt ril.so is using this private class * so changing the NetlinkListener() constructor breaks their ril. */ NetlinkListener:NetlinkListener(int socket) : SocketListener(socket, false) mFormat = NETLINK_FORMAT_ASCII; cpp view plain copy 在CODE上查看代码片派生到我的代码片SocketListener:SocketListener(const char *socketName, bool listen) init(socketName, -1, listen, false); void SocketListener:init(const char *socketName, int socketFd, bool listen, bool useCmdNum) mListen = listen;/是否是监听端,这里为false mSocketName = socketName;/保存socket的名字 mSock = socketFd;/保存socket的句柄值,与Kernel通信 mUseCmdNum = useCmdNum; pthread_mutex_init(&mClientsLock, NULL); mClients = new SocketClientCollection();/集合对象,保存类型SocketClient为的变量;保存了socket通信中的客户端对象 再看NetlinkHandler:start()方法:cpp view plain copy 在CODE上查看代码片派生到我的代码片int NetlinkHandler:start() return this-startListener(); 实际调用的是SocketListener:startListener():cpp view plain copy 在CODE上查看代码片派生到我的代码片int SocketListener:startListener() return startListener(4); int SocketListener:startListener(int backlog) if (!mSocketName & mSock = -1) SLOGE(Failed to start unbound listener); errno = EINVAL; return -1; else if (mSocketName) if (mSock = android_get_control_socket(mSocketName) 0) SLOGE(Obtaining file descriptor socket %s failed: %s, mSocketName, strerror(errno); return -1; SLOGV(got mSock = %d for %s, mSock, mSocketName); fcntl(mSock, F_SETFD, FD_CLOEXEC); if (mListen & listen(mSock, backlog) push_back(new SocketClient(mSock, false, mUseCmdNum);/创建一个SocketClient对象,并保存到集合中 if (pipe(mCtrlPipe) SLOGE(pipe failed (%s), strerror(errno); return -1; if (pthread_create(&mThread, NULL, SocketListener:threadStart, this) /创建一个线程,在其中调用threadStart(),根据mListen值,等待接收来自Kernel的Uevent消息 SLOGE(pthread_create (%s), strerror(errno); return -1; return 0; 创建一个SocketListener对象,并加入mClients中;随后,创建一个线程,并调用SocketListener:threadStart():cpp view plain copy 在CODE上查看代码片派生到我的代码片void *SocketListener:threadStart(void *obj) SocketListener *me = reinterpret_cast(obj); me-runListener(); pthread_exit(NULL); return NULL; void SocketListener:runListener() SocketClientCollection pendingList; while(1) SocketClientCollection:iterator it; fd_set read_fds; int rc = 0; int max = -1; FD_ZERO(&read_fds); if (mListen) max = mSock; FD_SET(mSock, &read_fds); FD_SET(mCtrlPipe0, &read_fds); if (mCtrlPipe0 max) max = mCtrlPipe0; pthread_mutex_lock(&mClientsLock); for (it = mClients-begin(); it != mClients-end(); +it) / NB: calling out to an other object with mClientsLock held (safe) int fd = (*it)-getSocket(); FD_SET(fd, &read_fds); if (fd max) max = fd; pthread_mutex_unlock(&mClientsLock); SLOGV(mListen=%d, max=%d, mSocketName=%s, mListen, max, mSocketName); if (rc = select(max + 1, &read_fds, NULL, NULL, NULL) 0) if (errno = EINTR) continue; SLOGE(select failed (%s) mListen=%d, max=%d, strerror(errno), mListen, max); sleep(1); continue; else if (!rc) continue; if (FD_ISSET(mCtrlPipe0, &read_fds) char c = CtrlPipe_Shutdown; TEMP_FAILURE_RETRY(read(mCtrlPipe0, &c, 1); if (c = CtrlPipe_Shutdown) break; continue; if (mListen & FD_ISSET(mSock, &read_fds) /mListener实际为false;监听端,有客户端连接请求 struct sockaddr addr; socklen_t alen; int c; do alen = sizeof(addr); c = accept(mSock, &addr, &alen);/接受client的连接请求,c是代表client套接字的文件描述符 SLOGV(%s got %d from accept, mSocketName, c); while (c 0 & errno = EINTR); if (c push_back(new SocketClient(c, true, mUseCmdNum);/根据c,创建一个SocketListener对象,并加入到队列中 pthread_mutex_unlock(&mClientsLock); /* Add all active clients to the pending list first */ pendingList.clear(); pthread_mutex_lock(&mClientsLock); for (it = mClients-begin(); it != mClients-end(); +it) SocketClient* c = *it; / NB: calling out to an other object with mClientsLock held (safe) int fd = c-getSocket(); if (FD_ISSET(fd, &read_fds) /遍历所有保存的客户端;有数据可读,将该套接字加入到队列中 pendingList.push_back(c); c-incRef(); pthread_mutex_unlock(&mClientsLock); /* Process the pending list, since it is owned by the thread, * there is no need to lock it */ while (!pendingList.empty() /* Pop the first item from the list */ it = pendingList.begin(); SocketClient* c = *it; pendingList.erase(it); /* Process it, if false is returned, remove from list */ if (!onDataAvailable(c) /客户端收到数据,调用NetlinkListener:onDataAvailable()处理 release(c, false);/数据处理失败,则释放socket资源 c-decRef(); 我们初始化NetlinkListener时传入的mListener值为false;上述代码中,会遍历所有保存的客户端socket,如果收到数据,则进行处理。调用NetlinkListener:onDataAvailable():cpp view plain copy 在CODE上查看代码片派生到我的代码片bool NetlinkListener:onDataAvailable(SocketClient *cli) int socket = cli-getSocket(); ssize_t count; uid_t uid = -1; bool require_group = true; if (mFormat = NETLINK_FORMAT_BINARY_UNICAST) require_group = false; count = TEMP_FAILURE_RETRY(uevent_kernel_recv(socket, mBuffer, sizeof(mBuffer), require_group, &uid);/从kernel获取Uevent消息,保存到mBuffer中 if (count 0) LOG_EVENT_INT(65537, uid); SLOGE(recvmsg failed (%s), strerror(errno); return false;/读取失败,则返回false,上层调用则会关闭socket资源 NetlinkEvent *evt = new NetlinkEvent();/事件的代码封装 if (evt-decode(mBuffer, count, mFormat) /解析Uevent数据,填充到NetlinkEvent对象中 onEvent(evt);/NetlinkHandler:onEvent() else if (mFormat != NETLINK_FORMAT_BINARY) / Dont complain if parseBinaryNetlinkMessage returns false. That can / just mean that the buffer contained no messages were interested in. SLOGE(Error decoding NetlinkEvent); delete evt; return true; 先通过socket获取到Uevent数据,再解析并将信息封装到NetlinkEvent对象中。NetlinkHandler:onEvent()分发处理该对象:cpp view plain copy 在CODE上查看代码片派生到我的代码片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) /如果Uevent是block子系统 vm-handleBlockEvent(evt);/进入VolumeManager中处理;此处和VolumeManager进行交互 如果事件是和外部存储有关,则调用VolumeManager:handleBlockEvent()处理该事件;这里,就看到了NetlinkManager和VolumeManager之间进行数据流动的处理了。(2)、VolumeManagerVold使用VolumeManager的过程和NetlinkManager类似,也是三步:vm= VolumeManager:Instance()vm-setBroadcaster(SocketListener *) cl)vm-start()1、2步与NetlinkManager的处理类似:cpp view plain copy 在CODE上查看代码片派生到我的代码片/单例模式 VolumeManager *VolumeManager:Instance() if (!sInstance) sInstance = new VolumeManager(); return sInstance; VolumeManager:VolumeManager() mDebug = false; mActiveContainers = new AsecIdCollection(); mBroadcaster = NULL; mUmsSharingCount = 0; mSavedDirtyRatio = -1; / set dirty ratio to 0 when UMS is active mUmsDirtyRatio = 0; void setBroadcaster(SocketListener *sl) mBroadcaster = sl; 直接看VolumeManager:start()的处理:cpp view plain copy 在CODE上查看代码片派生到我的代码片int VolumeManager:start() / Always start from a clean slate by unmounting everything in / directories that we own, in case we crashed. unmountAll();/在处理外部设备事件之前,先重置所有状态 / Assume that we always have an emulated volume on internal / storage; the framework will decide if it should be mounted. CHECK(mInternalEmulated = nullptr); mInternalEmulated = std:shared_ptr( new android:vold:EmulatedVolume(/data/media); mInternalEmulated-create();/预先设定/data/media,由framework决定是否mount;EmulatedVolume和VolumeBase之间是继承关系,代表不同类型的Volume return 0; 再直接看NetlinkManager和VolumeManager直接信息处理的调用:cpp vie
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 四川铁道职业学院《塑料加工技术》2023-2024学年第二学期期末试卷
- 山西财经大学《针灸医籍选》2023-2024学年第二学期期末试卷
- 武夷山职业学院《医学科研方法入门及设计》2023-2024学年第二学期期末试卷
- 浙江纺织服装职业技术学院《中医内科学及研究》2023-2024学年第一学期期末试卷
- 四川省通江县2024-2025学年初三下学期5月模拟考试生物试题试卷含解析
- 四川省绵阳富乐国际2025年中考模拟考试化学试题理工类试卷含解析
- 唐山市迁安市2025年五下数学期末达标测试试题含答案
- 四川省绵阳第五中学2025年中考模拟最后十套:化学试题(七)考前提分仿真卷含解析
- 浙江警官职业学院《电工电子技术(下)》2023-2024学年第二学期期末试卷
- 潍坊医学院《工程项目经济管理与建筑法规》2023-2024学年第二学期期末试卷
- GB/T 788-1999图书和杂志开本及其幅面尺寸
- GB/T 756-2010旋转电机圆柱形轴伸
- GB/T 6172.1-2000六角薄螺母
- GB/T 19189-2011压力容器用调质高强度钢板
- 公司合格供应商清单
- GB/T 13007-2011离心泵效率
- 2022年物流仓储行业REITs研究
- 政治学基础课件全部终稿
- 朱兰质量手册课件
- 小猪佩奇Peppa-Pig第一季1-2集英文台词
- 一园青菜成了精-课件
评论
0/150
提交评论