android usb挂载分析---vold处理FrameWork层发出的消息
来源:互联网 发布:阿里云校园扶持计划 编辑:程序博客网 时间:2024/05/17 21:54
Framework层收到消息后,又向vold发送了volume mount的消息,所以vold层又继续着处理这个消息,先看下大概处理流程:
同FrameWork层阻塞在等待vold的消息一样,vold层也在等待着收到 FrameWork层的消息,不过是调用select函数百阻塞,因为这个还有内核可能会有其它的连接请求的到来等,所以不能阻塞。
我们看下代码:
void SocketListener::runListener() { . . . if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { SLOGE("select failed (%s)", strerror(errno)); sleep(1); continue; } . . . if (FD_ISSET(fd, &read_fds)) { pthread_mutex_unlock(&mClientsLock); if (!onDataAvailable(*it)) { close(fd); pthread_mutex_lock(&mClientsLock); delete *it; it = mClients->erase(it); pthread_mutex_unlock(&mClientsLock); } FD_CLR(fd, &read_fds); pthread_mutex_lock(&mClientsLock); continue; }}
收到消息后,调用onDataAvailable,这里这个函数的实现是在FrameworkListener类中,在onDataAvailable中接收数据,并调用dispatchCommand对分发命令:
void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) { . . . for (i = mCommands->begin(); i != mCommands->end(); ++i) { FrameworkCommand *c = *i; if (!strcmp(argv[0], c->getCommand())) { if (c->runCommand(cli, argc, argv)) { SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno)); } goto out; } }}
mCommands中的命令是在什么时候加进去的?回顾下CommandListener的初始化,我们注册了很多的命令,对的,就是在注册这些命令的时候加进去的,这里传下来的命令是volume mount ,所以调用 VolumeCmd::runCommand
int CommandListener::VolumeCmd::runCommand(SocketClient *cli, int argc, char **argv) { . . . else if (!strcmp(argv[1], "mount")) { if (argc != 3) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false); return 0; } rc = vm->mountVolume(argv[2]);...}
针对mount命令,调用mountVolume,mountVolume中继续调用mountVol:
int Volume::mountVol() { dev_t deviceNodes[4]; int n, i, rc = 0; char errmsg[255]; if (getState() == Volume::State_NoMedia) { snprintf(errmsg, sizeof(errmsg), "Volume %s %s mount failed - no media", getLabel(), getMountpoint()); mVm->getBroadcaster()->sendBroadcast( ResponseCode::VolumeMountFailedNoMedia, errmsg, false); errno = ENODEV; return -1; } else if (getState() != Volume::State_Idle) { errno = EBUSY; return -1; } if (isMountpointMounted(getMountpoint())) { SLOGW("Volume is idle but appears to be mounted - fixing"); setState(Volume::State_Mounted); // mCurrentlyMountedKdev = XXX return 0; } n = getDeviceNodes((dev_t *) &deviceNodes, 4); if (!n) { SLOGE("Failed to get device nodes (%s)\n", strerror(errno)); return -1; } for (i = 0; i < n; i++) { char devicePath[255]; int result = 0; const char *disktype = "fat"; sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(deviceNodes[i]), MINOR(deviceNodes[i])); SLOGI("%s being considered for volume %s\n", devicePath, getLabel()); errno = 0; setState(Volume::State_Checking); result = Fat::check(devicePath); if(result) { result = Ntfs::check(devicePath); if(!result) { disktype = "ntfs"; } } if (result) { if (errno == ENODATA) { SLOGW("%s does not contain a FAT(Ntfs) filesystem\n", devicePath); continue; } errno = EIO; /* Badness - abort the mount */ SLOGE("%s failed FS checks (%s)", devicePath, strerror(errno)); setState(Volume::State_Idle); return -1; } /* * Mount the device on our internal staging mountpoint so we can * muck with it before exposing it to non priviledged users. */ errno = 0; if(0 == strcmp(disktype, "fat")) { if (Fat::doMount(devicePath, "/mnt/secure/staging", false, false,false, 1000, 1015, 0702, true)) { SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno)); continue; } } else if(0 == strcmp(disktype, "ntfs")) { if (Ntfs::doMount(devicePath, "/mnt/secure/staging", false, false,false, 1000, 1015, 0702, true)) { SLOGE("%s failed to mount via NTFS (%s)\n", devicePath, strerror(errno)); continue; } } SLOGI("Device %s, target %s mounted @ /mnt/secure/staging", devicePath, getMountpoint()); protectFromAutorunStupidity(); if (createBindMounts()) { SLOGE("Failed to create bindmounts (%s)", strerror(errno)); umount("/mnt/secure/staging"); setState(Volume::State_Idle); return -1; } /* * Now that the bindmount trickery is done, atomically move the * whole subtree to expose it to non priviledged users. */ if (doMoveMount("/mnt/secure/staging", getMountpoint(), false)) { SLOGE("Failed to move mount (%s)", strerror(errno)); umount("/mnt/secure/staging"); setState(Volume::State_Idle); return -1; } setState(Volume::State_Mounted); mCurrentlyMountedKdev = deviceNodes[i]; return 0; } SLOGE("Volume %s found no suitable devices for mounting :(\n", getLabel()); setState(Volume::State_Idle); return -1;}
mountVol中首先检票Volume的状态,这里面必须为State_Idle状态才会进行后面的操作,这里有一点需要注意下,我们知道,在DirectVolume::handleDiskAdded的时候 向FrameWork层发送VolumeDiskInserted消息,这个时候 FrameWork层才下发volume mount消息,但是这个时候Voleme的State为State_Pending,要等到内核将这块设备的所有分区的add消息发出并调用完handlePartitionAdded才将Volume的状态设为State_Idle,这里会不会发生这种情况:FrameWork消息已经发下来了要进行mount了,但add分区的消息还没处理完,这个时候Volume的状态仍为State_Pending,所以在这里mountVol检查状态的时候不正确,直接返回失败,因为在我们的项目中发现有的时候存储设备会挂载不上,所以这里加了一个延时处理,状态不对时,睡眠一会再处理。状态检查之后调用getDeviceNodes获取有多少分区,然后对所有分区一一进行挂载,注意挂载的时候是先挂载到/mnt/secure/staging,然后现调用doMoveMount移动到挂载点。
- android usb挂载分析---vold处理FrameWork层发出的消息
- android usb挂载分析---vold处理FrameWork层发出的消息
- android usb挂载分析---FrameWork层处理vold消息
- android usb挂载分析---FrameWork层处理收到的vold消息
- android usb挂载分析---vold处理内核消息
- android usb挂载分析---vold处理内核消息
- android usb挂载分析---vold处理内核消息
- android usb挂载分析----vold启动
- android usb挂载分析----vold启动
- android usb挂载分析----vold启动
- android usb挂载分析----vold启动
- Android2.2 Vold 分析-(四)---Vold 消息接收及挂载/卸载处理部分分析
- Android2.2 Vold 分析-(四)---Vold 消息接收及挂载/卸载处理部分分析
- Android Framework分析 ---- 1消息处理机制 java层
- Android2.2 Vold 消息接收及挂载/卸载处理部分分析
- Android4.4----Vold挂载管理分析USB挂载(二)
- Android4.4----Vold挂载管理分析USB挂载(三)
- Android4.4----Vold挂载管理分析USB挂载(四)
- 优化你的PowerBuilder程序
- 塔木德故事-注重学习
- 浏览器操作系统开发功能设想:新记忆功能
- SQL中where 和 having的区别
- 采用Sybase、PowerBuilder、Notes构建B/S应用系统
- android usb挂载分析---vold处理FrameWork层发出的消息
- 用PB做一个通用右键菜单
- 自己动手写的Web服务器<一>
- ubunt 用 cmake 编译OGRE
- Android 常用适配器总结
- 计算机体系结构(一)——进制
- 在PowerBuilder中创建图标栏应用
- 如何在PB中同时“继承”多个用户自定义数据窗口对象
- 用PowerBuilder制作指示灯