Vold是用于管理和控制Android外部存储介质的后台进程,这里说的管控,主要包括SD卡的插拔、挂载/卸载和格式化等;它是Android平台外部存储系统的管控枢纽。
Vold的整个控制模块主要由三个类模块构成:NetlinkManager、VolumeManager和CommandListener,它们的功能划分大概是:
- NetlinkManager:用于从kernel中获取SD卡插拔的Uevnet消息
- VolumeManager:管理模块,对NetlinkManager转发的消息做一些处理,并通过CommandListener发送给framework(MountService.java);接着framework会通过套接字下发命令,指引VolumeManager对存储设备做下一步的操作,如挂载/卸载等
- CommandListener:通过socket,实现MountService.java与Vold之间的消息交换
NetLink是Linux下用户进程和kernel进行信息交互的一种机制,借助这种机制,用户进程(如Vold/Netd)可以接收来自kernel的一些消息,同时也可以向kernel发送一些控制命令。NetlinkManager就是基于此设计的。Uevent也跟Linux系统有关,它与Linux 的设备文件系统有一定关系;这里,我们可以简单的认为,Uevent就是一个字符串,它描述了外部存储设备插入/拔出、挂载/卸载的状态信息。Vold通过Netlink机制,可以得到这些信息,并进行外部存储设备的管理、控制。
由上述介绍,我们可以得到如下的Vold框架图描述:
有了Vold的架构描述,接下来就开始分析Vold进程的整体流程及实现了。
一、Vold进程的声明与创建
Vold进程的声明与创建过程跟zygote一样,在init.rc中声明,在init进程创建:
- 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
- socket vold stream 0660 root mount
- socket cryptd stream 0660 root mount
- ioprio be 2
在创建Vold进程时,会为它创建两个socket,用于与framework进行信息交互。其他的细节,参考之前zygote进程创建的介绍。
二、进入Vold主程序
Vold的主程序在/system/vold目录中,直接看main.cpp::main()函数:
- int main(int argc, char** argv) {
- setenv("ANDROID_LOG_TAGS", "*:v", 1);
- android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
-
- LOG(INFO) << "Vold 3.0 (the awakening) firing up";
-
- LOG(VERBOSE) << "Detected support for:"
- << (android::vold::IsFilesystemSupported("ext4") ? " ext4" : "")
- << (android::vold::IsFilesystemSupported("f2fs") ? " f2fs" : "")
- << (android::vold::IsFilesystemSupported("vfat") ? " vfat" : "");
-
- VolumeManager *vm;
- CommandListener *cl;
- CryptCommandListener *ccl;
- NetlinkManager *nm;
-
- parse_args(argc, argv);
-
- sehandle = selinux_android_file_context_handle();
- if (sehandle) {
- selinux_android_set_sehandle(sehandle);
- }
-
-
- fcntl(android_get_control_socket("vold"), F_SETFD, FD_CLOEXEC);
- fcntl(android_get_control_socket("cryptd"), F_SETFD, FD_CLOEXEC);
-
- mkdir("/dev/block/vold", 0755);
-
-
- klog_set_level(6);
-
-
-
- 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 (property_get_bool("vold.debug", false)) {
- vm->setDebug(true);
- }
-
-
- cl = new CommandListener();
- ccl = new CryptCommandListener();
- vm->setBroadcaster((SocketListener *) cl);
- nm->setBroadcaster((SocketListener *) cl);
-
-
- if (vm->start()) {
- PLOG(ERROR) << "Unable to start VolumeManager";
- exit(1);
- }
-
- if (process_config(vm)) {
- PLOG(ERROR) << "Error reading configuration... continuing anyways";
- }
-
-
- if (nm->start()) {
- PLOG(ERROR) << "Unable to start NetlinkManager";
- exit(1);
- }
-
- coldboot("/sys/block");
-
-
-
-
-
-
- if (cl->startListener()) {
- PLOG(ERROR) << "Unable to start CommandListener";
- exit(1);
- }
-
-
- if (ccl->startListener()) {
- PLOG(ERROR) << "Unable to start CryptCommandListener";
- exit(1);
- }
-
-
- while(1) {
- sleep(1000);
- }
-
- LOG(ERROR) << "Vold exiting";
- exit(0);
- }
从代码中的注释可知,Vold主要创了三个对象:NetlinkManager、VolumeManager和CommandListener。根据Vold的架构图,现分别对它们的创建及启动过程进行分析。
(1)、NetlinkManager
主要的处理过程:
- nm = NetlinkManager::Instance()
- nm->setBroadcaster((SocketListener *) cl)
- nm->start()
现按步骤进行分析。
1、NetlinkManager::Instance():
- NetlinkManager *NetlinkManager::Instance() {
- if (!sInstance)
- sInstance = new NetlinkManager();
- return sInstance;
- }
-
- NetlinkManager::NetlinkManager() {
- mBroadcaster = NULL;
- }
这里使用了单例模式来构建NetlinkManager对象,构造函数中只是简单地初始化了成员变量。
2、NetlinkManager::setBroadcaster():
- cl = new CommandListener();
- nm->setBroadcaster((SocketListener *) cl);
- void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
setBroadcaster()函数也很简单,为mBroadcast进行赋值。
3、NetlinkManager::start():
- 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) {
- SLOGE("Unable to create uevent socket: %s", strerror(errno));
- return -1;
- }
-
-
- if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
- SLOGE("Unable to set uevent socket SO_RCVBUFFORCE option: %s", strerror(errno));
- goto out;
- }
-
- if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
- SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
- goto out;
- }
-
-
- if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
- SLOGE("Unable to bind uevent socket: %s", strerror(errno));
- goto out;
- }
-
- mHandler = new NetlinkHandler(mSock);
- if (mHandler->start()) {
- SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
- goto out;
- }
-
- return 0;
-
- out:
- close(mSock);
- return -1;
- }
start()方法中创建了一个句柄值为mSock的套接字,用来和kernel通信;而实际具体的socket信息交互是由NetlinkHandler处理的。
NetlinkHandler的实现有一套继承机制,其实际继承关系如图所示:
按照继承关系,分析它的构建过程:
- mHandler = new NetlinkHandler(mSock);
- NetlinkHandler::NetlinkHandler(int listenerSocket) :
- NetlinkListener(listenerSocket) {
- }
-
-
-
-
- NetlinkListener::NetlinkListener(int socket) :
- SocketListener(socket, false) {
- mFormat = NETLINK_FORMAT_ASCII;
- }
- SocketListener::SocketListener(const char *socketName, bool listen) {
- init(socketName, -1, listen, false);
- }
- void SocketListener::init(const char *socketName, int socketFd, bool listen,