这一节主要学习存储相关源码,Android的存储系统主要由SystemSever进程中的MountService和Vold进程中的VolumeManager组成,它们管理着系统的存储设备,执行各种操作,包括mount、unmount、format等。在Android的存储系统中,MountService是为应用提供服务的Binder类,运行在SystemServer中,而StorageManager是MountServer的代理,在用户进程中使用的。Vold是一个守护进程,负责和底层存储系统的驱动交互。MountService和Vold之间通过socket进行通信,这个通信过程是双问的,有从MountService到Vold的操作命令,也有从Vold到MountServcie的消息,用来通知底层硬件发生了变化。
Vold进程的主体是VolumeManager对象,它管理着系统底层所有Volume对象,实现各种存储相关的操作。NtelinkMananger对象的主要作用是创建NetlinkHandler对象。
1 管理存储设备——Vold 守护进程
Vold 的全称是 Volume Daemon.用来管理各种存储设备,包括外置 USB和 SD卡设备,MountService 通过 Vold 进程查询和操作这些存储设备。如果外部存储设备发生变化,例如,插入了USB设备,Vold将会接收到内核的UEvent消息并转发给MountService。
1.1 Vold的main函数
Vold 也是通过 init进程启动,它在vold.rc中的定义如下:
/system/vold/vold.rcservice 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:s0class coreioprio be 2writepid /dev/cpuset/foreground/tasksshutdown criticalgroup root reserved_disk
vold服务放到了core分组,这就意味着这系统启动时它就会被init进程启动。
vold模块的源码位于目录system/vold,先看看它的入口函数main(),代码如下:
/system/vold/main.cppint main(int argc, char** argv) {atrace_set_tracing_enabled(false);setenv("ANDROID_LOG_TAGS", "*:d", 1); // Do not submit with verbose logs enabledandroid::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));VolumeManager* vm;NetlinkManager* nm;parse_args(argc, argv);sehandle = selinux_android_file_context_handle();if (sehandle) {selinux_android_set_sehandle(sehandle);}mkdir("/dev/block/vold", 0755); //创建void目录/* For when cryptfs checks and mounts an encrypted filesystem */klog_set_level(6);/* Create our singleton managers */if (!(vm = VolumeManager::Instance())) { //创建VolumeManager对象LOG(ERROR) << "Unable to create VolumeManager";exit(1);}if (!(nm = NetlinkManager::Instance())) { //创建NetlinkManager对象LOG(ERROR) << "Unable to create NetlinkManager";exit(1);}if (android::base::GetBoolProperty("vold.debug", false)) {vm->setDebug(true);}if (vm->start()) {PLOG(ERROR) << "Unable to start VolumeManager";exit(1);}bool has_adoptable;bool has_quota;bool has_reserved;if (process_config(vm, &has_adoptable, &has_quota, &has_reserved)) {PLOG(ERROR) << "Error reading configuration... continuing anyways";}android::hardware::configureRpcThreadpool(1, false /* callerWillJoin */);ATRACE_BEGIN("VoldNativeService::start");if (android::vold::VoldNativeService::start() != android::OK) { //启动VoldNativeServiceLOG(ERROR) << "Unable to start VoldNativeService";exit(1);}ATRACE_END();LOG(DEBUG) << "VoldNativeService::start() completed OK";ATRACE_BEGIN("NetlinkManager::start");if (nm->start()) {PLOG(ERROR) << "Unable to start NetlinkManager";exit(1);}...// Do coldboot here so it won't block booting,// also the cold boot is needed in case we have flash drive// connected before Vold launchedcoldboot("/sys/block"); //创建/sys/block下的节点文件ATRACE_END();android::IPCThreadState::self()->joinThreadPool();LOG(INFO) << "vold shutting down";exit(0);
}
无论是VolumeManager对象还是NetlinkManager对象都是通过(aidl)跨进程通信。
1.2 监听驱动发出的消息——Vold的NetlinkManager 对象
NetlinkManager对象主要的工作是临听驱动发出的 uevent 消息。main()函数中调用NetlinkManager类的静态函数Instance()来创建NetlinkManager对象,代码如下:
NetlinkManager* NetlinkManager::Instance() {if (!sInstance) sInstance = new NetlinkManager();return sInstance;
}
Instance()函数创建了NetlinkManager对象并通过静态变量sInstance来引用,这意味着vold进程中只会有一个NetlinkManager对象。NetlinkManager的构造函数如下所示:
NetlinkManager::NetlinkManager() {mBroadcaster = NULL;
}
NetlinkManager 的构造函数只是对变量 mBroadcaster 进行了初始化。main()函数中会调用NetlinkManager的setBroadcaster()函数来给变量mBroadcaster重新赋值。
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;
}/system/vold/NetlinkHandler.cppvoid NetlinkHandler::onEvent(NetlinkEvent* evt) {VolumeManager* vm = VolumeManager::Instance();const char* subsys = evt->getSubsystem();if (!subsys) {LOG(WARNING) << "No subsystem found in netlink event";return;}if (std::string(subsys) == "block") {vm->handleBlockEvent(evt);}
}
/system/vold/VolumeManager.cppvoid VolumeManager::handleBlockEvent(NetlinkEvent* evt) {std::lock_guard lock(mLock);if (mDebug) {LOG(DEBUG) << "----------------";LOG(DEBUG) << "handleBlockEvent with action " << (int)evt->getAction();evt->dump();}std::string eventPath(evt->findParam("DEVPATH") ? evt->findParam("DEVPATH") : "");std::string devType(evt->findParam("DEVTYPE") ? evt->findParam("DEVTYPE") : "");if (devType != "disk") return;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// specific to virtual platforms; see Utils.cpp for details)// devices are SD, and that everything else is USBint flags = source->getFlags();if (major == kMajorBlockMmc || IsVirtioBlkDevice(major)) {flags |= android::vold::Disk::Flags::kSd;} else {flags |= android::vold::Disk::Flags::kUsb;}auto disk =new android::vold::Disk(eventPath, device, source->getNickname(), flags);handleDiskAdded(std::shared_ptr(disk));break;}}break;}case NetlinkEvent::Action::kChange: {LOG(DEBUG) << "Disk at " << major << ":" << minor << " changed";handleDiskChanged(device);break;}case NetlinkEvent::Action::kRemove: {handleDiskRemoved(device);break;}default: {LOG(WARNING) << "Unexpected block event action " << (int)evt->getAction();break;}}
}