Vold: Volume Daemon,用于管理和控制Android平台外部存储设备的后台进程,这些管理和控制,包括SD卡的插拔事件检测/SD卡挂载/卸载/格式化等.
9.0以前framework java层(StorageManagerService)和native层(Vold)的通信是socket,9.0以后使用binder通信.本文通过SD卡挂载流程,分析binder在vold服务中的使用.
vold服务在开机的时候会启动.定义于system/vold/vold.rc文件中:
service vold /system/bin/vold \
--blkid_context=u:r:blkid:s0 --blkid_untrusted_context=u:r:blkid_untrusted:s0 \
--fsck_context=u:r:fsck:s0 --fsck_untrusted_context=u:r:fsck_untrusted:s0
class core
ioprio be 2
writepid /dev/cpuset/foreground/tasks
shutdown critical
group reserved_disk
被init进程启动后,将调用system/vold/main.cpp中的main函数,然后初始化VolumeManager,NetlinkManager等等.初始化Vold服务.
在看下StorageManagerService的初始化.StorageManagerService由SystemServer启动,我们简单看看它的启动流程:
//调用SystemServiceManager的startService
mSystemServiceManager.startService(STORAGE_MANAGER_SERVICE_CLASS);
最终的实现如下:
public void startService(@NonNull final SystemService service) {
// Register it.
mServices.add(service);
// Start it.
long time = SystemClock.elapsedRealtime();
try {
//调用服务的onStart方法.
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + service.getClass().getName()
+ ": onStart threw an exception", ex);
}
warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
}
//StorageManagerService的onStart方法如下:
@Override
public void onStart() {
//创建StorageManagerService
mStorageManagerService = new StorageManagerService(getContext());
//将StorageManagerService注册到ServiceManager中
publishBinderService("mount", mStorageManagerService);
//调用StorageManagerService的start方法
mStorageManagerService.start();
}
private void start() {
connect();
}
//主要建立和Vold的通信,获取mVold对象,与Vold进程通信.
private void connect() {
IBinder binder = ServiceManager.getService("storaged");
if (binder != null) {
try {
//为binder对象设置死亡代理。当binder死亡后重新建立连接.
binder.linkToDeath(new DeathRecipient() {
@Override
public void binderDied() {
Slog.w(TAG, "storaged died; reconnecting");
mStoraged = null;
connect();
}
}, 0);
} catch (RemoteException e) {
binder = null;
}
}
if (binder != null) {
mStoraged = IStoraged.Stub.asInterface(binder);
} else {
Slog.w(TAG, "storaged not found; trying again");
}
binder = ServiceManager.getService("vold");
if (binder != null) {
try {
//为binder对象设置死亡代理。当binder死亡后重新建立连接.
binder.linkToDeath(new DeathRecipient() {
@Override
public void binderDied() {
Slog.w(TAG, "vold died; reconnecting");
mVold = null;
connect();
}
}, 0);
} catch (RemoteException e) {
binder = null;
}
}
if (binder != null) {
//通过binder机制,获取mVold对象(mVold就是IVold对象,这是一个代理类,具体实现在VoldNativeService.cpp),从而和Vold进程进行通信.
mVold = IVold.Stub.asInterface(binder);
try {
//mListener是IVoldListener的具体实现,当vold进程中相关事件改变通过IVoldListener这个代理,通知StorageManagerService处理.
mVold.setListener(mListener);
} catch (RemoteException e) {
mVold = null;
Slog.w(TAG, "vold listener rejected; trying again", e);
}
} else {
Slog.w(TAG, "vold not found; trying again");
}
if (mStoraged == null || mVold == null) {
BackgroundThread.getHandler().postDelayed(() -> {
connect();
}, DateUtils.SECOND_IN_MILLIS);
} else {
onDaemonConnected();
}
}
至此,StorageManagerService和Vold进程启动并建立和通信.
在Android9.0:/system/vold/binder/android/os/路径下多了如下几个文件,用于binder通信,关于binder通信就不在过多介绍,网上有很多优秀的资料,大家可以查找阅读.
IVold.aidl
IVoldListener.aidl
IVoldTaskListener.aidl
说下VoldNativeService.cpp这个文件,是IVold的具体实现.例如当mVold这个代理对象去调用mount方法,通过binder机制最终调用到VoldNativeService的mount方法.从而实现跨进程通信,有兴趣的同学可以自己研究下中间调用过程这里不在叙述.
下面说下9.0上SD卡的挂载流程.
先来一张9.0SD卡挂载流程图:
我们知道Vold服务初始化的时候执行main函数,会初始化NetlinkManager,执行start方法,其中会创建一个NetlinkHandler,当底层Kernel发送消息Uevent,经过一系列处理,最终调用VolumeManager的handleBlockEvent处理消息.
其实NetlinkManager启动后就是创建一个可以接收Kernel消息的socket,并以此socket构建并启动NetlinkHandler。
可以预见NetlinkHandler将用来处理socket收到的信息。
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
VolumeManager *vm = VolumeManager::Instance();
//判断当前的Uevent消息是什么类型
const char *subsys = evt->getSubsystem();
if (!subsys) {
LOG(WARNING) << "No subsystem found in netlink event";
return;
}
//如果subsys类型是块设备,就调用handleBlockEvent处理该消息
if (std::string(subsys) == "block") {
vm->handleBlockEvent(evt);
}
}
下面vold服务开始真正处理SD卡挂载流程.
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
std::lock_guard lock(mLock);
...
std::string eventPath(evt->findParam("DEVPATH")?evt->findParam("DEVPATH"):"");
std::string devType(evt->findParam("DEVTYPE")?evt->findParam("DEVTYPE"):"");
//设备Type不为disk就返回
if (devType != "disk") return;
//major和minor分别表示该设备的主次设备号,二者联合起来可以识别一个设备.
int major = std::stoi(evt->findParam("MAJOR"));
int minor = std::stoi(evt->findParam("MINOR"));
dev_t device = makedev(major, minor);
switch (evt->getAction()) {
case NetlinkEvent::Action::kAdd: {
for (const auto& source : mDiskSources) {
if (source->matches(eventPath)) {
// For now, assume that MMC and virtio-blk (the latter is
// emulator-specific; see Disk.cpp for details) devices are SD,
// and that everything else is USB
int flags = source->getFlags();
if (major == kMajorBlockMmc
|| (android::vold::IsRunningInEmulator()
&& major >= (int) kMajorBlockExperimentalMin
&& major <= (int) kMajorBlockExperimentalMax)) {
flags |= android::vold::Disk::Flags::kSd;
} else {
flags |= android::vold::Disk::Flags::kUsb;
}
//新建一个Disk,用来保存当前磁盘信息.
auto disk = new android::vold::Disk(eventPath, device,
source->getNickname(), flags);
handleDiskAdded(std::shared_ptr(disk));
break;
}
}
break;
}
...
}
//处理磁盘插入,主要调用Disk.cpp的create方法.初始化Disk.
void VolumeManager::handleDiskAdded(const std::shared_ptr& disk) {
// For security reasons, if secure keyguard is showing, wait
// until the user unlocks the device to actually touch it
if (mSecureKeyguardShowing) {
LOG(INFO) << "Found disk at " << disk->getEventPath()
<< " but delaying scan due to secure keyguard";
mPendingDisks.push_back(disk);
} else {
disk->create();
mDisks.push_back(disk);
}
}
status_t Disk::create() {
CHECK(!mCreated);
mCreated = true;
//onDiskCreated,通过binder机制,通知StorageManagerService磁盘创建
auto listener = VolumeManager::Instance()->getListener();
if (listener) listener->onDiskCreated(getId(), mFlags);
//检查文件系统格式和读取文件分区列表.
readMetadata();
readPartitions();
...
return OK;
}
status_t Disk::readPartitions() {
...
Table table = Table::kUnknown;
bool foundParts = false;
for (const auto& line : output) {
auto split = android::base::Split(line, kSgdiskToken);
auto it = split.begin();
if (it == split.end()) continue;
if (*it == "DISK") {
if (++it == split.end()) continue;
if (*it == "mbr") {
table = Table::kMbr;
} else if (*it == "gpt") {
table = Table::kGpt;
} else {
LOG(WARNING) << "Invalid partition table " << *it;
continue;
}
} else if (*it == "PART") {
foundParts = true;
if (++it == split.end()) continue;
int i = 0;
if (!android::base::ParseInt(*it, &i, 1, maxMinors)) {
LOG(WARNING) << "Invalid partition number " << *it;
continue;
}
dev_t partDevice = makedev(major(mDevice), minor(mDevice) + i);
if (table == Table::kMbr) {
if (++it == split.end()) continue;
int type = 0;
if (!android::base::ParseInt("0x" + *it, &type)) {
LOG(WARNING) << "Invalid partition type " << *it;
continue;
}
switch (type) {
case 0x06: // FAT16
case 0x07: // HPFS/NTFS/exFAT
case 0x0b: // W95 FAT32 (LBA)
case 0x0c: // W95 FAT32 (LBA)
case 0x0e: // W95 FAT16 (LBA)
//创建SD卡的volume信息
createPublicVolume(partDevice);
break;
}
}
...
}
void Disk::createPublicVolume(dev_t device) {
auto vol = std::shared_ptr(new PublicVolume(device));
//如果只是分区的创建,走进判断里.
if (mJustPartitioned) {
LOG(DEBUG) << "Device just partitioned; silently formatting";
vol->setSilent(true);
vol->create();
vol->format("auto");
vol->destroy();
vol->setSilent(false);
}
mVolumes.push_back(vol);
vol->setDiskId(getId());
//调用VolumeBase的create方法.由于PublicVolume是VolumeBase的子类,且具体实现VolumeBase的方法,这里其实调用的是PublicVolume的doCreate方法.
vol->create();
}
status_t VolumeBase::create() {
CHECK(!mCreated);
mCreated = true;
status_t res = doCreate();
auto listener = getListener();
//onVolumeCreated,通过binder机制,通知StorageManagerService创建volume
if (listener) listener->onVolumeCreated(getId(),
static_cast(mType), mDiskId, mPartGuid);
setState(State::kUnmounted);
return res;
}
//这里走进了StorageManagerService,
@Override
public void onVolumeCreated(String volId, int type, String diskId, String partGuid) {
synchronized (mLock) {
final DiskInfo disk = mDisks.get(diskId);
//保存Volume的信息到VolumeInfo
final VolumeInfo vol = new VolumeInfo(volId, type, disk, partGuid);
mVolumes.put(volId, vol);
onVolumeCreatedLocked(vol);
}
}
@GuardedBy("mLock")
private void onVolumeCreatedLocked(VolumeInfo vol) {
//这里主要根据设备类型,设置挂载的Flag,最终通过handler发送挂载信息.
...
vol.mountUserId = mCurrentUserId;
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
} else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
} else {
Slog.d(TAG, "Skipping automatic mounting of " + vol);
}
}
lass StorageManagerServiceHandler extends Handler {
public StorageManagerServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
....
case H_VOLUME_MOUNT: {
final VolumeInfo vol = (VolumeInfo) msg.obj;
if (isMountDisallowed(vol)) {
Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");
break;
}
try {
slogi(TAG, "Cmd send volume mount from handler " + vol.id + " "
+ vol.mountFlags + " " + vol.mountUserId);
//发送挂载命令,
mVold.mount(vol.id, vol.mountFlags, vol.mountUserId);
slogi(TAG, "Cmd send volume mount from handler end " + vol.id + " "
+ vol.mountFlags + " " + vol.mountUserId);
} catch (Exception e) {
Slog.wtf(TAG, e);
}
break;
}
}
mVold.mount在VoldNativeService中处理.
binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountFlags,
int32_t mountUserId) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_ID(volId);
ACQUIRE_LOCK;
auto vol = VolumeManager::Instance()->findVolume(volId);
if (vol == nullptr) {
return error("Failed to find volume " + volId);
}
vol->setMountFlags(mountFlags);
vol->setMountUserId(mountUserId);
//调用VolumeBase的mount.
int res = vol->mount();
if ((mountFlags & MOUNT_FLAG_PRIMARY) != 0) {
VolumeManager::Instance()->setPrimary(vol);
}
return translate(res);
}
status_t VolumeBase::mount() {
if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) {
LOG(WARNING) << getId() << " mount requires state unmounted or unmountable";
return -EBUSY;
}
//设置当前状态为checking
setState(State::kChecking);
//调用子类PublicVolume的doMount方法.
status_t res = doMount();
if (res == OK) {
//设置挂载成功状态,向上通知onVolumeStateChanged.
setState(State::kMounted);
} else {
setState(State::kUnmountable);
}
return res;
}
//实现挂载,doMount函数做了大量工作,由于自己水平有限,这里面很多调用还摸不清,如有大神知道,请指点指点,后续我了解了也会更新上来.
status_t PublicVolume::doMount() {
readMetadata();
//查看SD卡是否为vfat格式,系统是否支持.
if (mFsType == "vfat" && vfat::IsSupported()) {
//调用文件系统check函数检查是否是vfat格式.
if (vfat::Check(mDevPath)) {
LOG(ERROR) << getId() << " failed filesystem check";
return -EIO;
}
} else if (mFsType == "exfat" && exfat::IsSupported()) {
if (exfat::Check(mDevPath)) {
LOG(ERROR) << getId() << " failed filesystem check";
return -EIO;
}
} else {
LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
return -EIO;
}
// Use UUID as stable name, if available
std::string stableName = getId();
if (!mFsUuid.empty()) {
stableName = mFsUuid;
}
mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str());
mFuseDefault = StringPrintf("/mnt/runtime/default/%s", stableName.c_str());
mFuseRead = StringPrintf("/mnt/runtime/read/%s", stableName.c_str());
mFuseWrite = StringPrintf("/mnt/runtime/write/%s", stableName.c_str());
setInternalPath(mRawPath);
if (getMountFlags() & MountFlags::kVisible) {
setPath(StringPrintf("/storage/%s", stableName.c_str()));
} else {
setPath(mRawPath);
}
if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
PLOG(ERROR) << getId() << " failed to create mount points";
return -errno;
}
if (mFsType == "vfat") {
//将设备节点挂载在mRawPath下.
if (vfat::Mount(mDevPath, mRawPath, false, false, false, AID_MEDIA_RW, AID_MEDIA_RW, 0007,
true)) {
PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
return -EIO;
}
} else if (mFsType == "exfat") {
if (exfat::Mount(mDevPath, mRawPath, AID_MEDIA_RW, AID_MEDIA_RW, 0007)) {
PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
return -EIO;
}
}
if (getMountFlags() & MountFlags::kPrimary) {
initAsecStage();
}
if (!(getMountFlags() & MountFlags::kVisible)) {
// Not visible to apps, so no need to spin up FUSE
return OK;
}
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)) {
PLOG(ERROR) << getId() << " failed to create FUSE mount points";
return -errno;
}
dev_t before = GetDevice(mFuseWrite);
if (!(mFusePid = fork())) {
if (getMountFlags() & MountFlags::kPrimary) {
if (execl(kFusePath, kFusePath,
"-u", "1023", // AID_MEDIA_RW
"-g", "1023", // AID_MEDIA_RW
"-U", std::to_string(getMountUserId()).c_str(),
"-w",
mRawPath.c_str(),
stableName.c_str(),
NULL)) {
PLOG(ERROR) << "Failed to exec";
}
} else {
if (execl(kFusePath, kFusePath,
"-u", "1023", // AID_MEDIA_RW
"-g", "1023", // AID_MEDIA_RW
"-U", std::to_string(getMountUserId()).c_str(),
mRawPath.c_str(),
stableName.c_str(),
NULL)) {
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(mFuseWrite)) {
LOG(VERBOSE) << "Waiting for FUSE to spin up...";
usleep(50000); // 50ms
nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME);
if (nanoseconds_to_milliseconds(now - start) > 5000) {
LOG(WARNING) << "Timed out while waiting for FUSE to spin up";
return -ETIMEDOUT;
}
}
/* sdcardfs will have exited already. FUSE will still be running */
if (TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, WNOHANG)) == mFusePid)
mFusePid = 0;
return OK;
}
参考:
http://blog.csdn.net/gaugamela/article https://blog.csdn.net/Gaugamela/article/details/52484058
邓平凡大神的<深入理解Android卷1>第九章 vold的原理与机制分析