Vold(volume Daemon),即Volume守护进程,用来管理Android中存储类的热拔插事件,处于Kernel和Framework之间,是两个层级连接的桥梁。先来看一下Vold在Android系统的整体架构。
该图主要包含了Framework和Vold进程的,Kernel和App层涉及的内容这里不再涉及,简单介绍一下。Vold主要是接收Kernel的uevent消息,然后通过NM(NetLinkManager)和VM(VolumeManager)处理,将消息传递到Framework的SM(StorageManager),最后SM会将数据存储下来,消息通知到在SM注册的服务和App。
Vold在系统中以守护进程存在,是一个单独的进程,首先来看下Vold的启动过程以及如何与Kernel和Framework建立的联系。
在init.rc中有start vold的命令会被init解析到,而start对应的函数do_start(const BuiltinArguments& args);即启动对应的service,对应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 root reserved_disk
接下来看一下vold的main函数(由于篇幅原因,只列出来部分主要过程),简要概括为以下几个过程:
int main(int argc, char** argv) {
android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM)); //初始化Log类
VolumeManager* vm;
NetlinkManager* nm;
parse_args(argc, argv);//解析参数
mkdir("/dev/block/vold", 0755);//创建vold节点,用来接收uevent消息;
if (!(vm = VolumeManager::Instance())) {
LOG(ERROR) << "Unable to create VolumeManager";
exit(1);
}
if (!(nm = NetlinkManager::Instance())) {
LOG(ERROR) << "Unable to create NetlinkManager";
exit(1);
}
if (vm->start()) { //启动vm
PLOG(ERROR) << "Unable to start VolumeManager";
exit(1);
}
android::hardware::configureRpcThreadpool(1, false /* callerWillJoin */);
ATRACE_BEGIN("VoldNativeService::start");
if (android::vold::VoldNativeService::start() != android::OK) { //启动aidl接口
LOG(ERROR) << "Unable to start VoldNativeService";
exit(1);
}
if (nm->start()) { //启动nm
PLOG(ERROR) << "Unable to start NetlinkManager";
exit(1);
}
android::IPCThreadState::self()->joinThreadPool(); //进入循环
LOG(INFO) << "vold shutting down";
exit(0);
}
接下来着重看一下3个start函数分别都做了什么。首先看一下VM:
int VolumeManager::start() {
ATRACE_NAME("VolumeManager::start");
// Always start from a clean slate by unmounting everything in
// directories that we own, in case we crashed.
unmountAll();
Devmapper::destroyAll();
Loop::destroyAll();
// Assume that we always have an emulated volume on internal
// storage; the framework will decide if it should be mounted.
CHECK(mInternalEmulated == nullptr);
mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>(
new android::vold::EmulatedVolume("/data/media"));
mInternalEmulated->create();
// Consider creating a virtual disk
updateVirtualDisk();
return 0;
}
从给到的注释来看,VM会先卸载掉对应文件夹中的所有东西,使之处于一个干净的状态,接着会构造出内置存储目录,也即/data/media,此处通过VolumeBase基类指针new了一个EmulatedVolume对象。在create函数中,执行了doCreate以及回调了onVolumeCreated,此处的listener则是SM服务,但是由于Vold启动较早,SystemServer还没有启动SM,所以这里getListener()得到的是空,后面SM启动完成后会重新触发。最后便是设置了当前存储设备的状态为unmounted。其中doCreate是虚函数,但是EmulatedVolume中并没有实现,所以最终还是调用了基类函数,也就直接返回了。最后根据给的注释可知,Vold会创建一个虚拟磁盘,即/data/misc/vold/virtual_disk。
status_t VolumeBase::create() {
CHECK(!mCreated);
mCreated = true;
status_t res = doCreate();
auto listener = getListener();
if (listener) {
listener->onVolumeCreated(getId(), static_cast<int32_t>(mType), mDiskId, mPartGuid);
}
setState(State::kUnmounted);
return res;
}
status_t VolumeBase::doCreate() {
return OK;
}
到这里,VM的启动过程基本上就结束了,至于/data/media的挂载过程放到后面的章节去阐述。接着按照顺序来看一下aidl接口的启动,连接着SM和vold。
status_t VoldNativeService::start() {
IPCThreadState::self()->disableBackgroundScheduling(true);
status_t ret = BinderService<VoldNativeService>::publish();
if (ret != android::OK) {
return ret;
}
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
ps->giveThreadPoolName();
return android::OK;
}
启动的过程相对比较简单,VoldNativeService继承自BinderService,start主要注册了接口,使其他服务可以通过IVold可以找到,然后启动线程。
最后就是NM了,同样来看一下start函数,内部建立了一个socket连接,用于接收所有的uevent事件,最后会new一个NetlinkHandler对象,并执行start函数,然后会调用NetlinkListener父类的startListener函数去监听event。
int NetlinkManager::start() {
struct sockaddr_nl nladdr;
int sz = 64 * 1024;
int on = 1;
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = getpid();
nladdr.nl_groups = 0xffffffff;
if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT)) < 0) {
PLOG(ERROR) << "Unable to create uevent socket";
return -1;
}
// When running in a net/user namespace, SO_RCVBUFFORCE will fail because
// it will check for the CAP_NET_ADMIN capability in the root namespace.
// Try using SO_RCVBUF if that fails.
if ((setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) &&
(setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0)) {
PLOG(ERROR) << "Unable to set uevent socket SO_RCVBUF/SO_RCVBUFFORCE option";
goto out;
}
if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
PLOG(ERROR) << "Unable to set uevent socket SO_PASSCRED option";
goto out;
}
if (bind(mSock, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0) {
PLOG(ERROR) << "Unable to bind uevent socket";
goto out;
}
mHandler = new NetlinkHandler(mSock);
if (mHandler->start()) {
PLOG(ERROR) << "Unable to start NetlinkHandler";
goto out;
}
return 0;
out:
close(mSock);
return -1;
}
到这里Vold的启动过程基本就结束了,后续Vold会监听kernel的uevent事件,然后处理转发通过Callback通知到SM,而Framework的服务以及App则可以通过SM去使用Vold处理Command。本篇着重讲了Vold进程的启动,下一篇着重看下各层级之间的联系是如何建立的。