Vold之VolumeManager3 模块分析

VolumeManager的作用:

VolumeManager主要是管理Android系统中的外部存储设备。NetlinkManager将外部存储设备发生的Uevent消息发送给VolumeManager,VolumeManager来处理这些消息。

vold中,使用VolumeManager的流程分为3个步骤:
1、获取VolumeManager对象实例。
2、调用start启动。
3、调用process_config初始化VolumeManager。

1、获取VolumeManager实例,单例模式,即全局只存在一个对象。

VolumeManager *VolumeManager::sInstance = NULL;

VolumeManager *VolumeManager::Instance() {
    if (!sInstance)
        sInstance = new VolumeManager();
    return sInstance;
}

2、start方法

int VolumeManager::start() {
    return 0;
}

3、process_config初始化VolumeManager。
system/vold/Main.cpp

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);

            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);
        }
    }

    ret = 0;

out_fail:
    return ret;
}

3.1、首先获取ro.hardware,并初始化fstab_filename。

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);

我的手机获取到的ro.hardware为:qcom,FSTAB_PREFIX = /fstab.、
故:fstab_filename为:/fstab.qcom
3.2、读取fstab_filename中的内容,我的手机中内容如下;

# Android fstab file.
# 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

#TODO: Add 'check' as fs_mgr_flags with data partition.
# Currently we dont have e2fsck compiled. So fs check would failed.

#<src> <mnt_point> <type> <mnt_flags and options> <fs_mgr_flags>
/dev/block/bootdevice/by-name/system    /system            ext4    ro,barrier=1,noatime                                wait
/dev/block/bootdevice/by-name/userdata  /data              ext4    nosuid,nodev,barrier=1,noauto_da_alloc,noatime      wait,encryptable=footer
/devices/soc.0/f98a4900.sdhci/mmc_host  /storage/sdcard1   vfat    nosuid,nodev                                        wait,voldmanaged=sdcard1:auto
/devices/soc.0/f9a55000.ehci/usb1       /storage/uicc0     vfat    nosuid,nodev                                        wait,voldmanaged=uicc0:auto
/devices/soc.0/f9a55000.ehci/usb1       /storage/uicc1     vfat    nosuid,nodev                                        wait,voldmanaged=uicc1:auto
/devices/soc.0/f9200000.ssusb/f9200000.dwc3/xhci-hcd.0.auto/usb1  auto  auto  defaults                   wait,voldmanaged=usbotg:auto

从上面来看,我们可以得到如下信息:/dev/block/bootdevice/by-name/system标示挂载点,system标示volume的名称,ext4标示volume的格式等等。
3.3、构造DirectVolume,并执行addPath操作。

3.3.1、DirectVolume实例

DirectVolume::DirectVolume(VolumeManager *vm, const fstab_rec* rec, int flags) :
        Volume(vm, rec, flags) {
    mPaths = new PathCollection();
    for (int i = 0; i < MAX_PARTITIONS; i++)
        mPartMinors[i] = -1;
    mPendingPartCount = 0;
    mDiskMajor = -1;
    mDiskMinor = -1;
    mDiskNumParts = 0;
    mIsDecrypted = 0;
    mIsValid = true;

    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);//设定状态为NoMedia
}

3.3.2、addPath操作

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

3.4、VolumeManager执行addVolume操作。

vm->addVolume(dv);

4、NetlinkManager在收到底层信息后,会回调onEvent方法,进而会调用VolumeManager的相应方法。
NetLInkManager.cpp

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);
    }
}

从上面的代码来看,NetlinkManager收到Uevent会调用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) {
        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 } }

最后会执行DirectVolume的handleBlockEvent方法。
4.1、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)) {

            /* Check for UICC prefix in label */
            if (strstr(getLabel(), "uicc")) {
                char mLabel[15];
                int mNum = getUICCVolumeNum(dp);
                if (mNum < 0) {
                    SLOGE("Invalid uicc volume number");
                    continue;
                }

                snprintf(mLabel, sizeof(mLabel), "uicc%d", mNum);
                if (strncmp(getLabel(), mLabel, strlen(mLabel)) != 0)
                    continue;
            }
            setValidSysfs(true);

            /* 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上报的DEVPATH是否在自己corver范围之内:
4.1.1、判断是否在自己的corver范围之内:

PathCollection::iterator  it;
    for (it = mPaths->begin(); it != mPaths->end(); ++it) {
        if ((*it)->match(dp)) { /* Check for UICC prefix in label */ if (strstr(getLabel(), "uicc")) { char mLabel[15]; int mNum = getUICCVolumeNum(dp); if (mNum < 0) { SLOGE("Invalid uicc volume number"); continue; }

如果不在,continue。
4.1.2、下面继续,说明我们能够处理此Uevent,那么获取Uevent的action。

int action = evt->getAction();

大体能够处理的action有以下:

if (action == NetlinkEvent::NlActionAdd) 
else if (action == NetlinkEvent::NlActionRemove)
else if (action == NetlinkEvent::NlActionChange)
。。。。。。。

你可能感兴趣的:(vold)