Android(安卓)Vold简介(一)
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函数(由于篇幅原因,只列出来部分主要过程),简要概括为以下几个过程:
- 初始化Log函数;
- 解析rc中的参数,创建vold块设备节点;
- 获取NM和VM单例对象;
- 启动NM、VoldNativeService和VM;
- 创建线程池,并进入循环,维持进程不退出;
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进程的启动,下一篇着重看下各层级之间的联系是如何建立的。
更多相关文章
- C语言函数的递归(上)
- Android(安卓)OpenGL ES
- Android与ok6410板子tcp通信
- Android之——杀死用户选中的进程优化
- [置顶] AIDL使用以及原理分析
- Android(安卓)OkHttp的Cookie自动化管理
- Android(安卓)IPC机制(二)——利用Messenger实现跨进程通信
- Android判断手机中的应用是否具有某些权限(例如小米手机中是否具
- android activity 生命周期详解