看了很长时间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(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;
- }
- 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容器
- }
- }
- }
- # 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;
- }
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);
- }
- 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(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;
- }
- 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;
- }
- 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>
- 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;
- }
- }
- }
- 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.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";
- }
- 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;
- }
- }
- 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;
- }
- 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
- }
- 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);
- }
- }
- }
- }