之前两篇主要介绍了Vold的架构以及运行机制,本篇主要来介绍下Vold是内置存储和外置存储的mount流程。前面已经介绍过,无论什么存储,最终都会调用doMount()这个虚函数,对于不同类型的则会有不同的mount流程(即挂在到不同的文件系统下);对于内置存储,使用EmulatedVolume类来处理,而外接sd卡或者OTG设备则基本上都使用PublicVolume类来处理,因此uevent传递上来的消息会通知到vold到底这个存储介质属于什么类型。
首先来看下EmulatedVolume处理流程,首先会判断Primary标志,表明是内置主要的存储,一般都会跑进这个逻辑,因为只有data分区下的存储才会走这边;接着创建/mnt/runtime/default/emulated等四个目录,这个是Google针对sdcardfs添加的用来处理app之间相互的访问权限。拥有不同权限的app会bind mount到对应的目录,例如只有读权限的app则会bind到/mnt/runtime/read/emulated。
status_t EmulatedVolume::doMount() {
// We could have migrated storage to an adopted private volume, so always
// call primary storage "emulated" to avoid media rescans.
std::string label = mLabel; //存储介质的卷名
if (getMountFlags() & MountFlags::kPrimary) {
label = "emulated";
}
mFuseDefault = StringPrintf("/mnt/runtime/default/%s", label.c_str()); //默认权限,一般是只读权限;
mFuseRead = StringPrintf("/mnt/runtime/read/%s", label.c_str()); //读权限
mFuseWrite = StringPrintf("/mnt/runtime/write/%s", label.c_str()); //写权限
mFuseFull = StringPrintf("/mnt/runtime/full/%s", label.c_str()); //所有权限
setInternalPath(mRawPath);
setPath(StringPrintf("/storage/%s", label.c_str()));
//创建对应的四个目录
if (fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||
fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||
fs_prepare_dir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT) ||
fs_prepare_dir(mFuseFull.c_str(), 0700, AID_ROOT, AID_ROOT)) {
PLOG(ERROR) << getId() << " failed to create mount points";
return -errno;
}
dev_t before = GetDevice(mFuseFull);
//创建子进程,启动sdcard进程来处理具体的挂在流程;
if (!(mFusePid = fork())) {
// clang-format off
if (execl(kFusePath, kFusePath, //执行sdcard进程
"-u", "1023", // AID_MEDIA_RW 挂载使用的uid
"-g", "1023", // AID_MEDIA_RW 挂载使用的gid
"-m",
"-w",
"-G",
"-i",
"-o",
mRawPath.c_str(),
label.c_str(),
NULL)) {
// clang-format on
PLOG(ERROR) << "Failed to exec";
}
LOG(ERROR) << "FUSE exiting";
_exit(1);
}
if (mFusePid == -1) {
PLOG(ERROR) << getId() << " failed to fork";
return -errno;
}
nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
while (before == GetDevice