深入分析vold、MountService(and5.1)

来源:互联网 发布:淘宝lolita代购 编辑:程序博客网 时间:2024/05/20 11:37

Vold:Volume Daemon,管理和控制Android平台外部存储设备的后台进程,包括SD卡的插拔时间检测、SD卡挂载、卸载、格式化等等。

MountService和Vold交互,比如会发送一些广播,是接受到了vold的信息之后采取的动作。另外也会向vold发送挂载SD卡等命令。


Vold中的NetlinkManager模块(NM)接受来自linux内核的uevent消息。例如SD卡插拔等动作会引起Kernel向NM发送uevent消息。

NM将这些消息转发给VolumManager模块(VM)。VM会对应做一些操作,然后把相关信息通过CommandListener(CL)发送给MountService,MountService根据收到的消息会发送相关的处理命令给VM做进一步的处理。例如:SD卡插入后,VM会将来自NM的“Disk Insert”消息发送给MountService,而后MountService则发送“Mount”给Vold,指示它挂载这个SD卡。

CL模块内部封装了一个socket用于跨进程通信。它在vold进程中属于监听端,而连接端是MountService。它一方面接受来自MountService的控制命令(例如卸载存储卡、格式化存储卡),另一方面VM和NM模块又会通过它将一些信息发送给MountService。


下面我们开始分析Vold代码:

先从main函数:

int main() {    VolumeManager *vm;    CommandListener *cl;    NetlinkManager *nm;    mkdir("/dev/block/vold", 0755);    klog_set_level(6);    if (!(vm = VolumeManager::Instance())) {//创建VolumeManager        SLOGE("Unable to create VolumeManager");        exit(1);    };    if (!(nm = NetlinkManager::Instance())) {//创建NetlinkManager        SLOGE("Unable to create NetlinkManager");        exit(1);    };    cl = new CommandListener();    vm->setBroadcaster((SocketListener *) cl);//设置Broadcaster用来vold向MountService通信    nm->setBroadcaster((SocketListener *) cl);    if (vm->start()) {        SLOGE("Unable to start VolumeManager (%s)", strerror(errno));        exit(1);    }    if (process_config(vm)) {//根据文件配置VM对象,后面详细介绍        SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno));    }    if (nm->start()) {        SLOGE("Unable to start NetlinkManager (%s)", strerror(errno));        exit(1);    }    coldboot("/sys/block");//通过往/sys/block目录下对应的uevent文件写入“add\n"来触发内核发送Uevent消息,通过这种方式得到这些设备的当前信息。//    coldboot("/sys/class/switch");    /*     * Now that we're up, we can respond to commands     */    if (cl->startListener()) {        SLOGE("Unable to start CommandListener (%s)", strerror(errno));        exit(1);    }    // Eventually we'll become the monitoring thread    while(1) {//无限循环        sleep(1000);    }    SLOGI("Vold exiting");    exit(0);}

接下来我们看下NetlinkManager模块:

NetlinkManager *NetlinkManager::Instance() {    if (!sInstance)        sInstance = new NetlinkManager();    return sInstance;}NetlinkManager::NetlinkManager() {    mBroadcaster = NULL;}int NetlinkManager::start() {    struct sockaddr_nl nladdr;    int sz = 64 * 1024;    int on = 1;    memset(&nladdr, 0, sizeof(nladdr));    nladdr.nl_family = AF_NETLINK;//用来接受内核的netlink消息    nladdr.nl_pid = getpid();    nladdr.nl_groups = 0xffffffff;    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_RCVBUFFORCE option: %s", strerror(errno));        goto out;    }    if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {        SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));        goto out;    }    if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {        SLOGE("Unable to bind uevent socket: %s", strerror(errno));        goto out;    }    mHandler = new NetlinkHandler(mSock);    if (mHandler->start()) {//主要看下NetlinkHandler        SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));        goto out;    }    return 0;out:    close(mSock);    return -1;}

而接下来我们看下NetlinkHandler

NetlinkHandler::NetlinkHandler(int listenerSocket) :                NetlinkListener(listenerSocket) {}NetlinkHandler::~NetlinkHandler() {}int NetlinkHandler::start() {    return this->startListener();}int NetlinkHandler::stop() {    return this->stopListener();}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")) {        vm->handleBlockEvent(evt);    }}

NetlinkHandler中的start调用了startListener函数,而NetlinkHandler继承了NetlinkListener类,因此看下NetlinkListener有没有startListener函数:

NetlinkListener::NetlinkListener(int socket) :                            SocketListener(socket, false) {    mFormat = NETLINK_FORMAT_ASCII;}#endifNetlinkListener::NetlinkListener(int socket, int format) :                            SocketListener(socket, false), mFormat(format) {}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));    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)) {        onEvent(evt);    } else if (mFormat != NETLINK_FORMAT_BINARY) {        // Don't complain if parseBinaryNetlinkMessage returns false. That can        // just mean that the buffer contained no messages we're interested in.        SLOGE("Error decoding NetlinkEvent");    }    delete evt;    return true;}

也没有,NetlinkListener继承了SocketListener类,再看看SocketListener类中有没有startListener函数,
int SocketListener::startListener() {    return startListener(4);}int SocketListener::startListener(int backlog) {    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;        }        SLOGV("got mSock = %d for %s", mSock, mSocketName);    }    if (mListen && listen(mSock, backlog) < 0) {        SLOGE("Unable to listen on socket (%s)", strerror(errno));        return -1;    } else if (!mListen)        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;}
SocketListener果然有startListener函数,开启了一个线程,再看看threadStart函数
void *SocketListener::threadStart(void *obj) {    SocketListener *me = reinterpret_cast<SocketListener *>(obj);    me->runListener();    pthread_exit(NULL);    return NULL;}
直接调用了runlistener,在runlistener使用了select进行了IO复用。

void SocketListener::runListener() {    SocketClientCollection pendingList;    while(1) {        SocketClientCollection::iterator it;        fd_set read_fds;        int rc = 0;        int max = -1;        FD_ZERO(&read_fds);        if (mListen) {            max = mSock;            FD_SET(mSock, &read_fds);        }        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) {            // NB: calling out to an other object with mClientsLock held (safe)            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);        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)) {            char c = CtrlPipe_Shutdown;            TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));            if (c == CtrlPipe_Shutdown) {                break;            }            continue;        }        if (mListen && FD_ISSET(mSock, &read_fds)) {            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) {            SocketClient* c = *it;            // NB: calling out to an other object with mClientsLock held (safe)            int fd = c->getSocket();            if (FD_ISSET(fd, &read_fds)) {                pendingList.push_back(c);                c->incRef();            }        }        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, remove from list */            if (!onDataAvailable(c)) {//onDataAviailable是一个虚函数在NetlinkListener类中有实现                release(c, false);            }            c->decRef();        }    }}

而在NetlinkListener类中的onDataAvailable函数中又调用了onEvent函数,而这个函数是一个虚函数在NetlinkHandler类中实现,如下:

void NetlinkHandler::onEvent(NetlinkEvent *evt) {    VolumeManager *vm = VolumeManager::Instance();//调用VolumeManager单例    const char *subsys = evt->getSubsystem();    if (!subsys) {        SLOGW("No subsystem found in netlink event");        return;    }    if (!strcmp(subsys, "block")) {        vm->handleBlockEvent(evt);//如果是这个子系统的继续调用VM的handleBlockEvent    }}

下面再看VolumeManager中的handleBlockEvent函数:

void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {    const char *devpath = evt->findParam("DEVPATH");    /* Lookup a volume to handle this device */    VolumeCollection::iterator it;    bool hit = false;    for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {//根据VolumeManager中的mVolumes一个个遍历去处理        if (!(*it)->handleBlockEvent(evt)) {#ifdef NETLINK_DEBUG            SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());#endif            hit = true;            break;        }    }    if (!hit) {#ifdef NETLINK_DEBUG        SLOGW("No volumes handled block event for '%s'", devpath);#endif    }}

VolumeManager中根据Volumes的list一个个去遍历根据每个volume的handleBlockEvent函数处理。接下来我们需要看,何时volume加入到VolumeManager中去的:答案是在main函数中调用了process_config函数,其根据配置文件配置VM对象。

static int process_config(VolumeManager *vm){    char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];    char propbuf[PROPERTY_VALUE_MAX];    int i;    int ret = -1;    int flags;    property_get("ro.hardware", propbuf, "");    snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);    fstab = fs_mgr_read_fstab(fstab_filename);    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);//新建DirectVolume对象            if (dv->addPath(fstab->recs[i].blk_device)) {//添加设备在sysfs中的路径                SLOGE("Failed to add devpath %s to volume %s",                      fstab->recs[i].blk_device, fstab->recs[i].label);                goto out_fail;            }            vm->addVolume(dv);//VM中加入DirectVolume对象        }    }    ret = 0;out_fail:    return ret;}

process_config主要是解析/etc/vold.fstab。这个文件就是设置一些存储设备的挂载点,并且在VM中添加了DirectVolume对象。

DirectVolume从Volume派生,可以看成是外部存储卡的代表。封装了加载、卸载存储卡、格式化等。

DirectVolume::DirectVolume(VolumeManager *vm, const fstab_rec* rec, int flags) :        Volume(vm, rec, flags) {//参数rec->label: “sdcard”  rec->mount_point: "/mnt/sdcard"     mPaths = new PathCollection();    for (int i = 0; i < MAX_PARTITIONS; i++)        mPartMinors[i] = -1;    mPendingPartCount = 0;    mDiskMajor = -1;    mDiskMinor = -1;    mDiskNumParts = 0;    mIsDecrypted = 0;    if (strcmp(rec->mount_point, "auto") != 0) {        ALOGE("Vold managed volumes must have auto mount point; ignoring %s",              rec->mount_point);    }    char mount[PATH_MAX];    snprintf(mount, PATH_MAX, "%s/%s", Volume::MEDIA_DIR, rec->label);    mMountpoint = strdup(mount);    snprintf(mount, PATH_MAX, "%s/%s", Volume::FUSE_DIR, rec->label);    mFuseMountpoint = strdup(mount);    setState(Volume::State_NoMedia);}

addPath函数,主要是添加设备在sysfs中的路径,把某个存储卡相关的设备路径与这个DirectVolume绑定到一起,这个设备路径和Uevent中的DEVPATH对应的,这样就可以根据Uevent的DEVPATH找到是哪个存储卡的DirectVolume发生了变动。不过一般手机只有一个存储卡接口,所以vold也只有一个DirectVolume。

int DirectVolume::addPath(const char *path) {    mPaths->push_back(new PathInfo(path));    return 0;}


继续回到主题,前面分析到VM中遍历mVolumes,去执行DirectVolume中的handleBlockEvent,如下

int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {    const char *dp = evt->findParam("DEVPATH");    PathCollection::iterator  it;    for (it = mPaths->begin(); it != mPaths->end(); ++it) {        if ((*it)->match(dp)) {//去看Uevent中的DEVPATH是否在mPaths中            /* We can handle this disk */            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)) {                    SLOGE("Error making device node '%s' (%s)", nodepath,                                                               strerror(errno));                }                if (!strcmp(devtype, "disk")) {                    handleDiskAdded(dp, evt);                } else {                    handlePartitionAdded(dp, evt);                }                /* Send notification iff disk is ready (ie all partitions found) */                if (getState() == Volume::State_Idle) {                    char msg[255];                    snprintf(msg, sizeof(msg),                             "Volume %s %s disk inserted (%d:%d)", getLabel(),                             getFuseMountpoint(), mDiskMajor, mDiskMinor);                    mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,                                                         msg, false);                }            } else if (action == NetlinkEvent::NlActionRemove) {                if (!strcmp(devtype, "disk")) {                    handleDiskRemoved(dp, evt);                } else {                    handlePartitionRemoved(dp, evt);                }            } else if (action == NetlinkEvent::NlActionChange) {                if (!strcmp(devtype, "disk")) {                    handleDiskChanged(dp, evt);                } else {                    handlePartitionChanged(dp, evt);                }            } else {                    SLOGW("Ignoring non add/remove/change event");            }            return 0;        }    }    errno = ENODEV;    return -1;}

上面函数就是内核发送的Uevent最后的处理函数,详细的分析我们最后通过一个SD卡插入的实例看。


下面我们分析下CommandListener,CommandListener在main函数中,实例化,并且调用startListener函数,而发现CommandListener中没有startListener函数,就去父类FrameworkListener中找,也没有再去FrameworkListener的父类SocketListener中找,前面分析NetlinkHandler已经分析过这个类,它会开启一个线程,并且在线程中使用select的IO复用监听socket(是由MountService传过来的数据),最后调用onDataAvailable虚函数,而FrameworkListener实现了这个函数,在onDataAvailable函数中调用了FrameworkListener::dispatchCommand函数,在这个函数最后会调用各个command中的runCommand。


下面直接通过一个SD卡插入的实例说明整个过程:

先看SD卡插入,的Uevent信息:

add@/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0ACTION=add //add表示设备插入动作 ,还有remove change动作//DEVPATH表示设备位于/sys目录中的设备路径DEVPATH=/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0//SUBSYSTEM表示该设备属于哪一类设备,block块设备,磁盘也属于这类,另外还有字符型设备SUBSYSTEM=blockMAJOR=179 //MAJOR和MINOR分别表示该设备的主次设备号,两者联合起来表示一个设备。MINOR=0DEVNAME=mmcblk0DEVTYPE=disk   //设备Type为diskNPARTS=3   //表示该SD卡上的分区,这里表示有3块分区SEQNUM=1357  //序号
DirectVolume会处理这个Uevent信息,

int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {    const char *dp = evt->findParam("DEVPATH");    PathCollection::iterator  it;    for (it = mPaths->begin(); it != mPaths->end(); ++it) {        if ((*it)->match(dp)) {            /* We can handle this disk */            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)) {                    SLOGE("Error making device node '%s' (%s)", nodepath,                                                               strerror(errno));                }                if (!strcmp(devtype, "disk")) {//是disk类型的                    handleDiskAdded(dp, evt);                } else {                    handlePartitionAdded(dp, evt);                }                /* Send notification iff disk is ready (ie all partitions found) */                if (getState() == Volume::State_Idle) {                    char msg[255];                    snprintf(msg, sizeof(msg),                             "Volume %s %s disk inserted (%d:%d)", getLabel(),                             getFuseMountpoint(), mDiskMajor, mDiskMinor);                    mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,                                                         msg, false);//给MountService发送VolumeDiskInserted信息                }            } else if (action == NetlinkEvent::NlActionRemove) {                if (!strcmp(devtype, "disk")) {                    handleDiskRemoved(dp, evt);                } else {                    handlePartitionRemoved(dp, evt);                }            } else if (action == NetlinkEvent::NlActionChange) {                if (!strcmp(devtype, "disk")) {                    handleDiskChanged(dp, evt);                } else {                    handlePartitionChanged(dp, evt);                }            } else {                    SLOGW("Ignoring non add/remove/change event");            }            return 0;        }    }    errno = ENODEV;    return -1;}

下面来看下handleDiskAdded函数

void DirectVolume::handleDiskAdded(const char * /*devpath*/,                                   NetlinkEvent *evt) {    mDiskMajor = atoi(evt->findParam("MAJOR"));    mDiskMinor = atoi(evt->findParam("MINOR"));    const char *tmp = evt->findParam("NPARTS");//分区数    if (tmp) {        mDiskNumParts = atoi(tmp);    } else {        SLOGW("Kernel block uevent missing 'NPARTS'");        mDiskNumParts = 1;    }    mPendingPartCount = mDiskNumParts;    for (int i = 0; i < MAX_PARTITIONS; i++)        mPartMinors[i] = -1;    if (mDiskNumParts == 0) {#ifdef PARTITION_DEBUG        SLOGD("Dv::diskIns - No partitions - good to go son!");#endif        setState(Volume::State_Idle);    } else {#ifdef PARTITION_DEBUG        SLOGD("Dv::diskIns - waiting for %d pending partitions", mPendingPartCount);#endif        setState(Volume::State_Pending);    }}

我们来分析下setState这个函数

void Volume::setState(int state) {    char msg[255];    int oldState = mState;    if (oldState == state) {//一样的状态        SLOGW("Duplicate state (%d)\n", state);        return;    }    if ((oldState == Volume::State_Pending) && (state != Volume::State_Idle)) {        mRetryMount = false;    }    mState = state;    SLOGD("Volume %s state changing %d (%s) -> %d (%s)", mLabel,         oldState, stateToStr(oldState), mState, stateToStr(mState));    snprintf(msg, sizeof(msg),             "Volume %s %s state changed from %d (%s) to %d (%s)", getLabel(),             getFuseMountpoint(), oldState, stateToStr(oldState), mState,             stateToStr(mState));    mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeStateChange,                                         msg, false);//给MountService发送VolumeStateChange信息}

接下来我们看看MountService收到VolumeDiskInserted信息后会怎么处理:

    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) {            /*             * 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.VolumeUuidChange) {            // Format: nnn <label> <path> <uuid>            final String path = cooked[2];            final String uuid = (cooked.length > 3) ? cooked[3] : null;            final StorageVolume vol = mVolumesByPath.get(path);            if (vol != null) {                vol.setUuid(uuid);            }        } else if (code == VoldResponseCode.VolumeUserLabelChange) {            // Format: nnn <label> <path> <label>            final String path = cooked[2];            final String userLabel = (cooked.length > 3) ? cooked[3] : null;            final StorageVolume vol = mVolumesByPath.get(path);            if (vol != null) {                vol.setUserLabel(userLabel);            }        } else if ((code == VoldResponseCode.VolumeDiskInserted) ||//插入设备                   (code == VoldResponseCode.VolumeDiskRemoved) ||                   (code == VoldResponseCode.VolumeBadRemoval)) {            // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)            // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)            // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)            String action = null;            final String label = cooked[2];            final String path = cooked[3];            int major = -1;            int minor = -1;            try {                String devComp = cooked[6].substring(1, cooked[6].length() -1);                String[] devTok = devComp.split(":");                major = Integer.parseInt(devTok[0]);                minor = Integer.parseInt(devTok[1]);            } catch (Exception ex) {                Slog.e(TAG, "Failed to parse major/minor", ex);            }            final StorageVolume volume;            final String state;            synchronized (mVolumesLock) {                volume = mVolumesByPath.get(path);                state = mVolumeStates.get(path);            }            if (code == VoldResponseCode.VolumeDiskInserted) {//如果是插入设备                new Thread("MountService#VolumeDiskInserted") {                    @Override                    public void run() {                        try {                            int rc;                            if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {//开启线程执行doMountVolume                                Slog.w(TAG, String.format("Insertion mount failed (%d)", rc));                            }                        } catch (Exception ex) {                            Slog.w(TAG, "Failed to mount media on insertion", ex);                        }                    }                }.start();            } else if (code == VoldResponseCode.VolumeDiskRemoved) {                /*                 * This event gets trumped if we're already in BAD_REMOVAL state                 */                if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {                    return true;                }                /* Send the media unmounted event first */                if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");                updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);                sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL);                if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed");                updatePublicVolumeState(volume, Environment.MEDIA_REMOVED);                action = Intent.ACTION_MEDIA_REMOVED;            } else if (code == VoldResponseCode.VolumeBadRemoval) {                if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");                /* Send the media unmounted event first */                updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);                sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL);                if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal");                updatePublicVolumeState(volume, Environment.MEDIA_BAD_REMOVAL);                action = Intent.ACTION_MEDIA_BAD_REMOVAL;            } else if (code == VoldResponseCode.FstrimCompleted) {                EventLogTags.writeFstrimFinish(SystemClock.elapsedRealtime());            } else {                Slog.e(TAG, String.format("Unknown code {%d}", code));            }            if (action != null) {                sendStorageIntent(action, volume, UserHandle.ALL);            }        } else {            return false;        }        return true;    }


    private int doMountVolume(String path) {        int rc = StorageResultCode.OperationSucceeded;        final StorageVolume volume;        synchronized (mVolumesLock) {            volume = mVolumesByPath.get(path);        }        if (!volume.isEmulated() && hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA)) {            Slog.w(TAG, "User has restriction DISALLOW_MOUNT_PHYSICAL_MEDIA; cannot mount volume.");            return StorageResultCode.OperationFailedInternalError;        }        if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path);        try {            mConnector.execute("volume", "mount", path);//mConnector是与vold通信部分,发送volume mount命令挂载磁盘        } catch (NativeDaemonConnectorException e) {//异常处理}

再回到vold中,看处理mount命令:

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();    int rc = 0;    if (!strcmp(argv[1], "list")) {        bool broadcast = argc >= 3 && !strcmp(argv[2], "broadcast");        return vm->listVolumes(cli, broadcast);    } else if (!strcmp(argv[1], "debug")) {        if (argc != 3 || (argc == 3 && (strcmp(argv[2], "off") && strcmp(argv[2], "on")))) {            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume debug <off/on>", false);            return 0;        }        vm->setDebug(!strcmp(argv[2], "on") ? true : false);    } else if (!strcmp(argv[1], "mount")) {//处理mount命令        if (argc != 3) {            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false);            return 0;        }        rc = vm->mountVolume(argv[2]);//调用mountVolume函数    }     。。。。。。。。。。    if (!rc) {        cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);//发送Okay消息返回    } else {        int erno = errno;        rc = ResponseCode::convertFromErrno();        cli->sendMsg(rc, "volume operation failed", true);    }    return 0;}

mountVolume函数如下:

int VolumeManager::mountVolume(const char *label) {    Volume *v = lookupVolume(label);//查找Volume    if (!v) {        errno = ENOENT;        return -1;    }    return v->mountVol();}

mountVol函数如下:

int Volume::mountVol() {    dev_t deviceNodes[4];    int n, i, rc = 0;    char errmsg[255];    int flags = getFlags();    bool providesAsec = (flags & VOL_PROVIDES_ASEC) != 0;    // TODO: handle "bind" style mounts, for emulated storage    char decrypt_state[PROPERTY_VALUE_MAX];    char crypto_state[PROPERTY_VALUE_MAX];    char encrypt_progress[PROPERTY_VALUE_MAX];    property_get("vold.decrypt", decrypt_state, "");    property_get("vold.encrypt_progress", encrypt_progress, "");    /* Don't try to mount the volumes if we have not yet entered the disk password     * or are in the process of encrypting.     */    if ((getState() == Volume::State_NoMedia) ||//还没初始化        ((!strcmp(decrypt_state, "1") || encrypt_progress[0]) && providesAsec)) {        snprintf(errmsg, sizeof(errmsg),                 "Volume %s %s mount failed - no media",                 getLabel(), getFuseMountpoint());        mVm->getBroadcaster()->sendBroadcast(                                         ResponseCode::VolumeMountFailedNoMedia,                                         errmsg, false);        errno = ENODEV;        return -1;    } else if (getState() != Volume::State_Idle) {//当前状态正忙        errno = EBUSY;        if (getState() == Volume::State_Pending) {            mRetryMount = true;        }        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);    。。。。。。。。    for (i = 0; i < n; i++) {        char devicePath[255];        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);        if (Fat::check(devicePath)) {            if (errno == ENODATA) {                SLOGW("%s does not contain a FAT 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;        }        errno = 0;        int gid;        //把设备mount一个地址        if (Fat::doMount(devicePath, getMountpoint(), false, false, false,                AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) {            SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno));            continue;        }        extractMetadata(devicePath);        if (providesAsec && mountAsecExternal() != 0) {            SLOGE("Failed to mount secure area (%s)", strerror(errno));            umount(getMountpoint());            setState(Volume::State_Idle);            return -1;        }        char service[64];        snprintf(service, 64, "fuse_%s", getLabel());        property_set("ctl.start", service);        setState(Volume::State_Mounted);//设置设备状态State_Mounted        mCurrentlyMountedKdev = deviceNodes[i];        return 0;    }    SLOGE("Volume %s found no suitable devices for mounting :(\n", getLabel());    setState(Volume::State_Idle);    return -1;}

设置设备状态State_Mounted会发送VolumeStateChange消息给MountService,当MountService收到后会发送广播

    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) {            /*             * 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]));        }

最后会在notifyVolumeStateChange发送广播:

  private void notifyVolumeStateChange(String label, String path, int oldState, int newState) {        final StorageVolume volume;        final String state;        synchronized (mVolumesLock) {            volume = mVolumesByPath.get(path);            state = getVolumeState(path);        }        if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChange::" + state);        String action = null;        if (oldState == VolumeState.Shared && newState != oldState) {            if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent");            sendStorageIntent(Intent.ACTION_MEDIA_UNSHARED, volume, UserHandle.ALL);        }        if (newState == VolumeState.Init) {        } else if (newState == VolumeState.NoMedia) {            // NoMedia is handled via Disk Remove events        } else if (newState == VolumeState.Idle) {            /*             * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or             * if we're in the process of enabling UMS             */            if (!state.equals(                    Environment.MEDIA_BAD_REMOVAL) && !state.equals(                            Environment.MEDIA_NOFS) && !state.equals(                                    Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) {                if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable");                updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);                action = Intent.ACTION_MEDIA_UNMOUNTED;            }        } else if (newState == VolumeState.Pending) {        } else if (newState == VolumeState.Checking) {            if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking");            updatePublicVolumeState(volume, Environment.MEDIA_CHECKING);            action = Intent.ACTION_MEDIA_CHECKING;        } else if (newState == VolumeState.Mounted) {            if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted");            updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED);            action = Intent.ACTION_MEDIA_MOUNTED;        } else if (newState == VolumeState.Unmounting) {            action = Intent.ACTION_MEDIA_EJECT;        } else if (newState == VolumeState.Formatting) {        } else if (newState == VolumeState.Shared) {            if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted");            /* Send the media unmounted event first */            updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);            sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL);            if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared");            updatePublicVolumeState(volume, Environment.MEDIA_SHARED);            action = Intent.ACTION_MEDIA_SHARED;            if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent");        } else if (newState == VolumeState.SharedMnt) {            Slog.e(TAG, "Live shared mounts not supported yet!");            return;        } else {            Slog.e(TAG, "Unhandled VolumeState {" + newState + "}");        }        if (action != null) {            sendStorageIntent(action, volume, UserHandle.ALL);        }    }
至此Vold、和MountService分析结束。




1 1
原创粉丝点击