我是靠谱客的博主 粗犷黑夜,最近开发中收集的这篇文章主要介绍android usb挂载分析---vold处理FrameWork层发出的消息,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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层发出的消息所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(51)

评论列表共有 0 条评论

立即
投稿
返回
顶部