vold挂载管理
来源:互联网 发布:linux echo 串口 编辑:程序博客网 时间:2024/05/16 13:01
看了很长时间Vold存储模块的相关知识,也深入的研究一段时间的Android源码,打算把自己看过的经验之贴、参考资料和自己的一些见解,以帖子的形式发出来,供有兴趣的同仁们参考,有不对的地方请指正,我们相互交流。
1.1 vold的原理与机制分析
1.1.1 Vold 架构
从上图中可知:
· Vold中的NetlinkManager模块接收来自Linux内核的uevent消息。例如SD卡的插拔等动作都会引起Kernel向NM发送uevent消息。
· NetlinkManager将这些消息转发给VolumeManager模块。VolumeManager会对应做一些操作,然后把相关信息通过CommandListener发送给MountService,MountService根据收到的消息会发送相关的处理命令给VolumeManager做进一步的处理。例如待SD卡插入后,VolumeManager会将来自NetlinkManager的“Disk Insert”消息发送给MountService,而后MountService则发送“Mount”指令给Vold,指示它挂载这个SD卡。
· CommandListener模块内部封装了一个Socket用于跨进程通信。它在Vold进程中属于监听端(即是服务端),而它的连接端(即客户端)则是MountService。它一方面接收来自MountService的控制命令(例如卸载存储卡、格式化存储卡等),另一方面VolumeManager和NetlinkManager模块又会通过它,将一些信息发送给MountService。
1.1.2初识Vold
下面来初步的认识Vold,代码在system\vold\main.cpp
int main() { mkdir("/dev/block/vold", 0755); //创建一个目录/dev/block/vold //创建一个VolumeManager对象,该对象为单例模式 if (!(vm = VolumeManager::Instance())) { SLOGE("Unable to create VolumeManager"); exit(1); }; //创建一个NetlinkManager对象,该对象为单例模式 if (!(nm = NetlinkManager::Instance())) { SLOGE("Unable to create NetlinkManager"); exit(1); }; //创建一个CommandListener对象 cl = new CommandListener(); vm->setBroadcaster((SocketListener *) cl); nm->setBroadcaster((SocketListener *) cl);//启动VolumeManager if (vm->start()) { SLOGE("Unable to start VolumeManager (%s)", strerror(errno)); exit(1); }//根据fstab配置文件初始化VolumeManager if (process_config(vm)) { SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno)); }//启动NetlinkManager对象 if (nm->start()) { SLOGE("Unable to start NetlinkManager (%s)", strerror(errno)); exit(1); }//通过往/sys/block目录下对应的uevent文件写“add\n”来触发内核发送Uevent消息 coldboot("/sys/block");//启动CommandListener if (cl->startListener()) { SLOGE("Unable to start CommandListener (%s)", strerror(errno)); exit(1); }}
1.2 NetlinkManager模块的分析
1.2.1 NetlinkManager架构流程图
1.2.2 start的分析
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; // 创建一个socket用于内核空间和用户空间的异步通信,监控系统的hotplug事件 if ((mSock = socket(PF_NETLINK, SOCK_DGRAM,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_RECBUFFORCE option: %s", strerror(errno)); return -1; } if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) { SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno)); return -1; } if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) { SLOGE("Unable to bind uevent socket: %s", strerror(errno)); return -1; } // 利用新创建的socket实例化一个NetlinkHandler类对象,NetlinkHandler继承了类NetlinkListener, // NetlinkListener又继承了类SocketListener mHandler = new NetlinkHandler(mSock); if (mHandler->start()) { //启动NetlinkHandler SLOGE("Unable to start NetlinkHandler: %s", strerror(errno)); return -1; } return 0; }NetlinkHandler构造
NetlinkHandler::NetlinkHandler(int listenerSocket) : NetlinkListener(listenerSocket) {}继承父类
NetlinkListener::NetlinkListener(int socket) : SocketListener(socket, false) { mFormat = NETLINK_FORMAT_ASCII;}
接着调用的start()函数,也是最终实现在SockListener的startListener()。
int NetlinkHandler::start() { return this->startListener(); } int SocketListener::startListener() { 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; } } if (mListen && listen(mSock, 4) < 0) { SLOGE("Unable to listen on socket (%s)", strerror(errno)); return -1; } else if (!mListen) mClients->push_back(new SocketClient(mSock, false)); if (pipe(mCtrlPipe)) { SLOGE("pipe failed (%s)", strerror(errno)); return -1; } if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) { SLOGE("pthread_create (%s)", strerror(errno)); return -1; } return 0; } void *SocketListener::threadStart(void *obj) { SocketListener *me = reinterpret_cast<SocketListener *>(obj); me->runListener(); pthread_exit(NULL); return NULL; } void SocketListener::runListener() { SocketClientCollection *pendingList = new SocketClientCollection(); while(1) { // 死循环,一直监听 SocketClientCollection::iterator it; fd_set read_fds; int rc = 0; int max = -1; FD_ZERO(&read_fds); //清空文件描述符集read_fds if (mListen) { max = mSock; FD_SET(mSock, &read_fds); //添加文件描述符到文件描述符集read_fds } FD_SET(mCtrlPipe[0], &read_fds); //添加管道的读取端文件描述符到read_fds if (mCtrlPipe[0] > max) max = mCtrlPipe[0]; pthread_mutex_lock(&mClientsLock); //对容器mClients的操作需要加锁 for (it = mClients->begin(); it != mClients->end(); ++it) { int fd = (*it)->getSocket(); FD_SET(fd, &read_fds); ////遍历容器mClients的所有成员,调用内联函数getSocket()获取文件描述符,并添加到文件描述符集read_fds if (fd > max) max = fd; } pthread_mutex_unlock(&mClientsLock); // 等待文件描述符中某一文件描述符或者说socket有数据到来 if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { if (errno == EINTR) continue; SLOGE("select failed (%s)", strerror(errno)); sleep(1); continue; } else if (!rc) continue; if (FD_ISSET(mCtrlPipe[0], &read_fds)) break; if (mListen && FD_ISSET(mSock, &read_fds)) { //监听套接字处理 struct sockaddr addr; socklen_t alen; int c; do { alen = sizeof(addr); c = accept(mSock, &addr, &alen); //接收链接请求,建立连接,如果成功c即为建立链接后的数据交换套接字,将其添加到mClient容器 } while (c < 0 && errno == EINTR); if (c < 0) { SLOGE("accept failed (%s)", strerror(errno)); sleep(1); continue; } pthread_mutex_lock(&mClientsLock); mClients->push_back(new SocketClient(c, true)); 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) { int fd = (*it)->getSocket(); if (FD_ISSET(fd, &read_fds)) { pendingList->push_back(*it); } } 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 and our sockets are * connection-based, remove and destroy it */ // ****** onDataAvailable在NetlinkListener中实现********* if (!onDataAvailable(c) && mListen) { /* Remove the client from our array */ pthread_mutex_lock(&mClientsLock); for (it = mClients->begin(); it != mClients->end(); ++it) { if (*it == c) { mClients->erase(it); break; } } pthread_mutex_unlock(&mClientsLock); /* Remove our reference to the client */ c->decRef(); } } } delete pendingList; }SocketListener::runListener是线程真正执行的函数:mListen成员用来判定是否监听套接字,Netlink套接字属于udp套接字,非监听套接字,该函数的主要功能体现在,如果该套接字有数据到来,就调用函数onDataAvailable读取数据
bool NetlinkListener::onDataAvailable(SocketClient *cli){ int socket = cli->getSocket(); ssize_t count; uid_t uid = -1; count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv( socket, mBuffer, sizeof(mBuffer), &uid)); //从socket中读取event信息 if (count < 0) { if (uid > 0) LOG_EVENT_INT(65537, uid); SLOGE("recvmsg failed (%s)", strerror(errno)); return false; } NetlinkEvent *evt = new NetlinkEvent(); if (!evt->decode(mBuffer, count, mFormat)) { //调用NetlinkEvent解析event SLOGE("Error decoding NetlinkEvent"); } else { onEvent(evt); //传递event给子类NetlinkHandler处理 } delete evt; return true;}
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")) { //EVENT为block类型 int action = evt->getAction(); vm->updatePullOutState(evt); vm->setHotPlug(true); vm->handleBlockEvent(evt); //把event交给<span style="font-family: Arial; line-height: 26px;">VolumeManager处理</span> vm->setHotPlug(false); }
1.2.3 NM模块的总结
1.3 VolumeManager模块的分析
1.3.1 Vold使用VM模块的流程
调用Instance创建一个VM对象。
调用setBroadcaster设置CL对象
调用start启动VM。
调用process_config配置VM。
1.3.2 VM的创建
VolumeManager *VolumeManager::Instance() { if (!sInstance) sInstance = new VolumeManager(); return sInstance;}
VolumeManager::VolumeManager() { mDebug = false; mVolumes = new VolumeCollection(); //一个容器,保存<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 15px; line-height: 35px;">Volume的集合</span> mActiveContainers = new AsecIdCollection(); mBroadcaster = NULL; //指向socketlisten,用于发送挂载事件 mUmsSharingCount = 0; mSavedDirtyRatio = -1; mUmsDirtyRatio = dirtyRatio(); mVolManagerDisabled = 0; mIsHotPlug= false; mUseBackupContainers =false; mIsFirstBoot = false; mIpoState = State_Ipo_Start;}
1.3.3 VM的启动
int VolumeManager::start() { return 0; //<span style="font-family: Arial; font-size: 14px; line-height: 26px;">VM的启动什么也没有做</span>}
1.3.4 process_config分析
static int process_config(VolumeManager *vm){ char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)]; fstab = fs_mgr_read_fstab(fstab_filename); //读取fstab文件 if (!fstab) { SLOGE("failed to open %s\n", fstab_filename); return -1; } /* Loop through entries looking for ones that vold manages */ for (i = 0; i < fstab->num_entries; i++) { if (fs_mgr_is_voldmanaged(&fstab->recs[i])) { DirectVolume *dv = NULL; flags = 0; /* Set any flags that might be set for this volume */ if (fs_mgr_is_nonremovable(&fstab->recs[i])) { flags |= VOL_NONREMOVABLE; } if (fs_mgr_is_encryptable(&fstab->recs[i])) { flags |= VOL_ENCRYPTABLE; } /* Only set this flag if there is not an emulated sd card */ if (fs_mgr_is_noemulatedsd(&fstab->recs[i]) && !strcmp(fstab->recs[i].fs_type, "vfat")) { flags |= VOL_PROVIDES_ASEC; } dv = new DirectVolume(vm, &(fstab->recs[i]), flags); if (dv->addPath(fstab->recs[i].blk_device)) { SLOGE("Failed to add devpath %s to volume %s", fstab->recs[i].blk_device, fstab->recs[i].label); goto out_fail; } vm->addVolume(dv); //添加到volumemanager容器 } }}fstab配置文件
# Android fstab file.#<src> <mnt_point> <type> <mnt_flags and options> <fs_mgr_flags># The filesystem that contains the filesystem checker binary (typically /system) cannot# specify MF_CHECK, and must come before any filesystems that do specify MF_CHECK/devices/platform/mtk-msdc.0/mmc_host auto vfat defaults voldmanaged=sdcard0:emmc@fat,noemulatedsd/devices/platform/mtk-msdc.1/mmc_host auto vfat defaults voldmanaged=sdcard1:auto
1.3.5 DirectVolume分析
DirectVolume::DirectVolume(VolumeManager *vm,const char *label, const char*mount_point, int partIdx) : Volume(vm, label, mount_point) {//初始化基类 /* 注意其中的参数: label为”sdcard”,mount_point为”/mnt/sdcard”,partIdx为1 */ mPartIdx = partIdx;//PathCollection定义为typedef android::List<char *> PathCollection//其实就是一个字符串list mPaths= new PathCollection(); for(int i = 0; i < MAX_PARTITIONS; i++) mPartMinors[i] = -1; mPendingPartMap = 0; mDiskMajor = -1; //存储设备的主设备号 mDiskMinor = -1; //存储设备的次设备号,一个存储设备将由主次两个设备号标识。 mDiskNumParts = 0; //设置状态为NoMedia setState(Volume::State_NoMedia);}//再来看addPath函数,它主要目的是添加设备在sysfs中的路径,int DirectVolume::addPath(const char *path) { mPaths->push_back(strdup(path)); return0;}addPath把和某个存储卡接口相关的设备路径与这个DirectVolume绑定到一起,并且这个设备路径和Uevent中的DEVPATH是对应的,这样就可以根据Uevent的DEVPATH找到是哪个存储卡的DirectVolume发生了变动。当然手机上目前只有一个存储卡接口,所以Vold也只有一个DirectVolume。
1.3.6 VM与NM交互
void VolumeManager::handleBlockEvent(NetlinkEvent*evt) { constchar *devpath = evt->findParam("DEVPATH"); /*前面在process_config中构造的DirectVolume对象保存在了mVolumes中,它的定义如下:typedef android::List<Volume *>VolumeCollection,也是一个列表。 注意它保存的是Volume指针,而我们的DirectVolume是从Volume派生的*/ VolumeCollection::iterator it; boolhit = false;for (it = mVolumes->begin(); it !=mVolumes->end(); ++it) { //调用每个Volume的handleBlockEvent事件,实际上将调用 //DirectVolume的handleBlockEvent函数。 if(!(*it)->handleBlockEvent(evt)) { hit = true; break; } }}
int DirectVolume::handleBlockEvent(NetlinkEvent*evt) { constchar *dp = evt->findParam("DEVPATH"); PathCollection::iterator it;//将Uevent的DEVPATH和addPath添加的路径进行对比,判断属不属于自己管理的范围。 for(it = mPaths->begin(); it != mPaths->end(); ++it) { if(!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 nodepath[255]; snprintf(nodepath, sizeof(nodepath),"/dev/block/vold/%d:%d", major, minor); //创建设备节点 if (createDeviceNode(nodepath, major, minor)) { ...... } if (!strcmp(devtype, "disk")) { handleDiskAdded(dp, evt);//添加一个磁盘 } else { /*对于有分区的SD卡,先收到上面的“disk”消息,然后每个分区就会收到 一个分区添加消息。 */ handlePartitionAdded(dp,evt); } } else if (action == NetlinkEvent::NlActionRemove) { ...... } else if (action == NetlinkEvent::NlActionChange) { ...... } ...... return 0; } } errno= ENODEV; return-1;}
1.4 commandlisten模块分析
1.4.1 commandlisten构造
cl = new CommandListener(); vm->setBroadcaster((SocketListener *) cl); nm->setBroadcaster((SocketListener *) cl); ... /* * Now that we're up, we can respond to commands */ if (cl->startListener()) { SLOGE("Unable to start CommandListener (%s)", strerror(errno)); exit(1); }构造函数/system/vold/CommandListener.cpp
CommandListener::CommandListener() : FrameworkListener("vold", true) { registerCmd(new DumpCmd()); registerCmd(new VolumeCmd()); registerCmd(new AsecCmd()); registerCmd(new ObbCmd()); registerCmd(new StorageCmd()); registerCmd(new XwarpCmd()); registerCmd(new CryptfsCmd()); registerCmd(new FstrimCmd()); //M{#ifndef MTK_EMULATOR_SUPPORT registerCmd(new USBCmd());#endif registerCmd(new CDROMCmd()); //}M#if defined (ENG_BUILD_ENG) registerCmd(new SilkRoad());#endif}构造一个父类FrameworkListener
FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) : SocketListener(socketName, true, withSeq) { init(socketName, withSeq); }
void FrameworkListener::init(const char *socketName, bool withSeq) { mCommands = new FrameworkCommandCollection(); errorRate = 0; mCommandCount = 0; mWithSeq = withSeq; }
SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) { init(socketName, -1, listen, useCmdNum);}
void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) { mListen = listen; mSocketName = socketName; mSock = socketFd; mUseCmdNum = useCmdNum; pthread_mutex_init(&mClientsLock, NULL); mClients = new SocketClientCollection();}
1.4.2 Command注册
void FrameworkListener::registerCmd(FrameworkCommand *cmd) { mCommands->push_back(cmd);}
CommandListener::VolumeCmd::VolumeCmd() : VoldCommand("volume") {}
VoldCommand::VoldCommand(const char *cmd) : FrameworkCommand(cmd) {}
FrameworkCommand::FrameworkCommand(const char *cmd) { mCommand = cmd;}
将volume这个command注册到mCommands这个容器中之后,目的是当FrameworkListerer从SlocketListener接收到command的时候,会依据mCommands 中的command进行解析筛选判断分发,调用对应的command执行类
1.4.3 startListener的分析和数据处理
int SocketListener::startListener() { 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) {//获取socket的文件描述符,这里是获取Vold这个socket的 SLOGE("Obtaining file descriptor socket '%s' failed: %s", mSocketName, strerror(errno)); return -1; } SLOGV("got mSock = %d for %s", mSock, mSocketName); } if (mListen && listen(mSock, 4) < 0) { SLOGE("Unable to listen on socket (%s)", strerror(errno)); return -1; } else if (!mListen)//是否正常监听socket mClients->push_back(new SocketClient(mSock, false, mUseCmdNum)); if (pipe(mCtrlPipe)) {//新建管道,保存文件描述符到数组 SLOGE("pipe failed (%s)", strerror(errno)); return -1; } if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {//开了一个线程来处理 SLOGE("pthread_create (%s)", strerror(errno)); return -1; } return 0; }开启线程用于监听
void *SocketListener::threadStart(void *obj) { SocketListener *me = reinterpret_cast<SocketListener *>(obj);//threadStart为static函数,上面开线程创建的时候传了this,这里需要转换一个一样bit位的SocketListener指针 me->runListener();//SocketListener真正的执行函数 pthread_exit(NULL); return NULL; }对socket监听处理
void SocketListener::runListener() { SocketClientCollection *pendingList = new SocketClientCollection();//暂存mClients中的SocketClient while(1) { SocketClientCollection::iterator it; fd_set read_fds; int rc = 0; int max = -1; FD_ZERO(&read_fds);//清空文件描述符集read_fds if (mListen) { max = mSock; FD_SET(mSock, &read_fds);//如果正常的监听,这里就把之前获得的vold的文件描述符添加进去 } FD_SET(mCtrlPipe[0], &read_fds);//添加管道读取端的文件描述符 if (mCtrlPipe[0] > max) max = mCtrlPipe[0]; pthread_mutex_lock(&mClientsLock);//加锁操作,多线程安全 for (it = mClients->begin(); it != mClients->end(); ++it) {//遍历mClients,获取fd 添加到read_fds 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); //linux下socket编程的select,这里检测read_fds集合里面是否有可读的,也就是有没有数据过来,没有数据的文件描述符会从read_fds中被剔除,这里的select设置time out为NULL,阻塞操作,直到read_fds集合中描述符有变化 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(mCtrlPipe[0], &read_fds))//如果匿名管道有数据可读,就退出 break; if (mListen && FD_ISSET(mSock, &read_fds)) {//如果是正常监听的 mListen 为true,然后mSock这个描述符有可读数据,就创建链接,新建异步处理的SocketClient加入到mClients容器,这里的mSock 是vold这个套接字的描述符 struct sockaddr addr; socklen_t alen; int c; do { alen = sizeof(addr); c = accept(mSock, &addr, &alen); SLOGV("%s got %d from accept", mSocketName, c); } while (c < 0 && errno == EINTR); if (c < 0) { SLOGE("accept failed (%s)", strerror(errno)); sleep(1); continue; } pthread_mutex_lock(&mClientsLock); mClients->push_back(new SocketClient(c, true, mUseCmdNum)); 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) {//把上面有请求建立链接的Client加入到pendingList 容器中,后面处理 int fd = (*it)->getSocket(); if (FD_ISSET(fd, &read_fds)) { pendingList->push_back(*it); } } 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 and our sockets are * connection-based, remove and destroy it */ if (!onDataAvailable(c) && mListen) {//调用到FrameworkListener 中onDataAvailable处理Socket事件 /* Remove the client from our array */ SLOGV("going to zap %d for %s", c->getSocket(), mSocketName); pthread_mutex_lock(&mClientsLock); for (it = mClients->begin(); it != mClients->end(); ++it) { if (*it == c) { mClients->erase(it);//处理完成之后,从容器中移除这次的监听到的SocketClient break; } } pthread_mutex_unlock(&mClientsLock); /* Remove our reference to the client */ c->decRef(); } } } delete pendingList; }SocketListener的核心处理函数是onDataAvailable
bool FrameworkListener::onDataAvailable(SocketClient *c) { char buffer[255]; int len; len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));//读Socket 内容保存到buffer if (len < 0) { SLOGE("read() failed (%s)", strerror(errno)); return false; } else if (!len) return false; int offset = 0; int i; for (i = 0; i < len; i++) { if (buffer[i] == '\0') {//一次传入一个字符串 <span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: rgb(240, 247, 254);"> //分发命令,最终会调用对应命令对象的runCommand进行函数处理。</span> dispatchCommand(c, buffer + offset); offset = i + 1; } } return true; } </span>调用dispatchcommand
void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) { FrameworkCommandCollection::iterator i; int argc = 0; char *argv[FrameworkListener::CMD_ARGS_MAX]; char tmp[255]; ...//解析判断command buffer for (i = mCommands->begin(); i != mCommands->end(); ++i) {//遍历之前register到FrameworkListener中的FrameworkCommand容器 FrameworkCommand *c = *i; if (!strcmp(argv[0], c->getCommand())) {//其中有注册“Volume”,如果这里是Volume开头的command,那么就调用,Volume构造的时候所构造的父类FrameworkCommand中的runCommand函数 if (c->runCommand(cli, argc, argv)) { SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno)); } goto out; } } }以Volume这个runcommand为例 /system/vold/CommandListener.cpp中
int CommandListener::VolumeCmd::runCommand(SocketClient *cli, int argc, char **argv) { dumpArgs(argc, argv, -1); if (argc < 2) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false); return 0; } VolumeManager *vm = VolumeManager::Instance();//获取已经存在的VolumeManager实例 ... else if (!strcmp(argv[1], "mount")) {//判断command 内容 if (argc != 3) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false); return 0; } rc = vm->mountVolume(argv[2]);//交给VolumeManager来对Volume进行操作 } ... }
1.4.4 commandlisten 数据处理流程图
1.5 mountservice模块的介绍
1.5.1 mountservice构造
public MountService(Context context) { mContext = context; synchronized (mVolumesLock) { readStorageListLocked(); // 解析/frameworks/base/core/res/res/xml/storage_list.xml保存volume到 MountService的list :mVolumes中 } // XXX: This will go away soon in favor of IMountServiceObserver mPms = (PackageManagerService) ServiceManager.getService("package"); mHandlerThread = new HandlerThread("MountService"); mHandlerThread.start(); mHandler = new MountServiceHandler(mHandlerThread.getLooper());//新建消息处理handler // Watch for user changes final IntentFilter userFilter = new IntentFilter(); userFilter.addAction(Intent.ACTION_USER_ADDED); userFilter.addAction(Intent.ACTION_USER_REMOVED); mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);//注册广播接收 // Watch for USB changes on primary volume final StorageVolume primary = getPrimaryPhysicalVolume(); if (primary != null && primary.allowMassStorage()) { mContext.registerReceiver( mUsbReceiver, new IntentFilter(UsbManager.ACTION_USB_STATE), null, mHandler); } // Add OBB Action Handler to MountService thread. mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper()); /* * Create the connection to vold with a maximum queue of twice the * amount of containers we'd ever expect to have. This keeps an * "asec list" from blocking a thread repeatedly. */ mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25);//创建 vold 的监听接收,用于接收system中Vold的socket消息 Thread thread = new Thread(mConnector, VOLD_TAG); thread.start();//启动线程,NativeDaemonConnector实现了Runnable接口,实现在 run中 // Add ourself to the Watchdog monitors if enabled. if (WATCHDOG_ENABLE) { Watchdog.getInstance().addMonitor(this); } }
1.5.2构造了NativeDaemonConnector用来接收来自下层的socket消息
NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket, int responseQueueSize, String logTag, int maxLogSize) { mCallbacks = callbacks; //回调 mSocket = socket; // socket名称 mResponseQueue = new ResponseQueue(responseQueueSize);//构建一个响应队列 mSequenceNumber = new AtomicInteger(0); TAG = logTag != null ? logTag : "NativeDaemonConnector"; }开启监测线程的run方法
public void run() { HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler"); //TAG 为 VoldConnector,这里新建一个名为VoldConnector.CallbackHandler的消息处理线程,用于下面接收到vold 的socket之后的处理 thread.start(); mCallbackHandler = new Handler(thread.getLooper(), this); //创建handler 用于分发消息 while (true) { try { listenToSocket();// while 循环 监听socket } catch (Exception e) { loge("Error in NativeDaemonConnector: " + e); SystemClock.sleep(5000); } } }
private void listenToSocket() throws IOException { LocalSocket socket = null; try { socket = new LocalSocket(); //创建本地socket LocalSocketAddress address = new LocalSocketAddress(mSocket, LocalSocketAddress.Namespace.RESERVED);//获得服务端vold socket的地址 socket.connect(address);//连接 InputStream inputStream = socket.getInputStream(); synchronized (mDaemonLock) { mOutputStream = socket.getOutputStream(); }//获取输入输出流 mCallbacks.onDaemonConnected();//回调,在MountService中执行,初始化一些Volume状态信息 byte[] buffer = new byte[BUFFER_SIZE]; int start = 0; while (true) { int count = inputStream.read(buffer, start, BUFFER_SIZE - start);//读取数据到buffer if (count < 0) {//连接断开,跳出当前while ,外部while循环 重新调用该函数连接 loge("got " + count + " reading with start = " + start); break; } // Add our starting point to the count and reset the start. count += start; start = 0; for (int i = 0; i < count; i++) { if (buffer[i] == 0) { final String rawEvent = new String( buffer, start, i - start, Charsets.UTF_8); log("RCV <- {" + rawEvent + "}"); try { final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent( rawEvent); //解析成event 保存 if (event.isClassUnsolicited()) { //判断event的code范围 code >= 600 && code < 700 // TODO: migrate to sending NativeDaemonEvent instances mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( //发送消息,把event交给handle来分发处理 event.getCode(), event.getRawEvent())); } else { mResponseQueue.add(event.getCmdNumber(), event);//加入到响应队列 } } catch (IllegalArgumentException e) { log("Problem parsing message: " + rawEvent + " - " + e); } start = i + 1; } }在NativeDaemonConnector中的handle处理为:
public boolean handleMessage(Message msg) { String event = (String) msg.obj; try { if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) { //回调到MountService 的onEent函数 log(String.format("Unhandled event '%s'", event)); } } catch (Exception e) { loge("Error handling '" + event + "': " + e); } return true; }MountService中onEvent
public boolean onEvent(int code, String raw, String[] cooked) { if (DEBUG_EVENTS) { StringBuilder builder = new StringBuilder(); builder.append("onEvent::"); builder.append(" raw= " + raw); if (cooked != null) { builder.append(" cooked = " ); for (String str : cooked) { builder.append(" " + str); } } Slog.i(TAG, builder.toString()); } if (code == VoldResponseCode.VolumeStateChange) { //根据 Vold的Code 执行 /* * One of the volumes we're managing has changed state. * Format: "NNN Volume <label> <path> state changed * from <old_#> (<old_str>) to <new_#> (<new_str>)" */ notifyVolumeStateChange( cooked[2], cooked[3], Integer.parseInt(cooked[7]), Integer.parseInt(cooked[10])); //更新状态 } else if ((code == VoldResponseCode.VolumeDiskInserted) || (code == VoldResponseCode.VolumeDiskRemoved) || (code == VoldResponseCode.VolumeBadRemoval)) ... if (code == VoldResponseCode.VolumeDiskInserted) { //如果接收到的是插入disk的消息,则执行挂载操作 new Thread() { @Override public void run() { try { int rc; if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { Slog.w(TAG, String.format("Insertion mount failed (%d)", rc)); } } catch (Exception ex) { Slog.w(TAG, "Failed to mount media on insertion", ex); } } }.start(); } }
1.5.3 MountService下发command
private int doMountVolume(String path) { int rc = StorageResultCode.OperationSucceeded; final StorageVolume volume; synchronized (mVolumesLock) { volume = mVolumesByPath.get(path); } if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path); try { mConnector.execute("volume", "mount", path);// 调用到NativeDaemonConnector中的execute }NativeDaemonConnector的execute
public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args) throws NativeDaemonConnectorException { final ArrayList<NativeDaemonEvent> events = Lists.newArrayList(); final int sequenceNumber = mSequenceNumber.incrementAndGet(); final StringBuilder cmdBuilder = new StringBuilder(Integer.toString(sequenceNumber)).append(' '); final long startTime = SystemClock.elapsedRealtime(); makeCommand(cmdBuilder, cmd, args); //转换制作成标准的Command final String logCmd = cmdBuilder.toString(); /* includes cmdNum, cmd, args */ log("SND -> {" + logCmd + "}"); cmdBuilder.append('\0'); final String sentCmd = cmdBuilder.toString(); /* logCmd + \0 */ synchronized (mDaemonLock) { if (mOutputStream == null) { throw new NativeDaemonConnectorException("missing output stream"); } else { try { mOutputStream.write(sentCmd.getBytes(Charsets.UTF_8)); //通过在listenToSocket中获取的输出流,写入转换好的sentCmd } catch (IOException e) { throw new NativeDaemonConnectorException("problem sending command", e); } } } }
1.5.4 Mountservice 数据处理流程图
- vold挂载管理
- vold挂载管理
- Android—— 4.2 Vold挂载管理_CommandListener (二)
- Android—— 4.2 Vold挂载管理_VolumeManager (三)
- Android—— 4.2 Vold挂载管理_NetlinkManager (四)
- Android—— 4.2 Vold挂载管理_MountService (六)
- Android—— 4.2 Vold挂载管理_Kernel_USB_Uevent (七)
- Android4.4----Vold挂载管理分析(一)
- Android4.4----Vold挂载管理分析USB挂载(二)
- Android4.4----Vold挂载管理分析USB挂载(三)
- Android4.4----Vold挂载管理分析USB挂载(四)
- Android—— 4.2 Vold挂载管理_主体构建main (一)
- Android—— 4.2 Vold挂载管理_DirectVolume/Volume (五)
- Android—— 4.2 Vold挂载管理_mmcblk内置-双sdcard (八)
- android vold磁盘管理
- android usb挂载分析----vold启动
- android usb挂载分析----vold启动
- android usb挂载分析----vold启动
- android开发笔记 -摄像头开发
- 安卓APP中WebView页面中定义字体
- Linux Centos下安装与设置Vim编辑器和基本配置
- 页面JS复制功能
- Android关于Dex拆分(MultiDex)技术的解析
- vold挂载管理
- CentOS7桌面版安装中文输入法
- 设计模式-单例
- 页面引导
- mongodb的sharding(分片)横向扩容的方法
- Android MD风格(仿饿了么透明状态栏) app换肤(夜间模式与日间模式主题切换)
- json 的优点
- java创建线程的三种方式及其对比
- 逻辑回归