Android源码笔记--存储
Posted ljt2724960661
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android源码笔记--存储相关的知识,希望对你有一定的参考价值。
这一节主要学习存储相关源码,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.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服务放到了core分组,这就意味着这系统启动时它就会被init进程启动。
vold模块的源码位于目录system/vold,先看看它的入口函数main(),代码如下:
/system/vold/main.cpp
int main(int argc, char** argv)
atrace_set_tracing_enabled(false);
setenv("ANDROID_LOG_TAGS", "*:d", 1); // Do not submit with verbose logs enabled
android::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) //启动VoldNativeService
LOG(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 launched
coldboot("/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.cpp
void 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.cpp
void VolumeManager::handleBlockEvent(NetlinkEvent* evt)
std::lock_guard<std::mutex> 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 USB
int 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<android::vold::Disk>(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;
以上是关于Android源码笔记--存储的主要内容,如果未能解决你的问题,请参考以下文章
Android Sqlite框架 GreenDao的源码分析笔记