概述
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 %sn", 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) filesystemn", 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层发出的消息所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复