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