文章目录
Volume Daemon,简写Vold,用于管理和控制Android平台外部存储设备的后台进程。这些管理或控制包括SD卡的插拔事件检测/SD卡挂载/卸载/格式化等。
记录一下Vold进程启动的源码分析,方便自己查阅。
Android P
这里很多都是网上的,我就走走流程。
先看看vold哪里启动的。
这里主要涉及目录的代码
\system\vold
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
至于何时加载,可以看看《》,init进程LoadBootScripts会添加/system/etc/init目录下的rc文件进行解析。
main.cpp
main()
int main(int argc, char** argv) { atrace_set_tracing_enabled(false); //设置日志等级 setenv("ANDROID_LOG_TAGS", "*:v", 1); //初始化日志 android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM)); VolumeManager *vm; NetlinkManager *nm; //解析参数,也就是vold.rc中带的 parse_args(argc, argv); sehandle = selinux_android_file_context_handle(); if (sehandle) { selinux_android_set_sehandle(sehandle); } //创建/dev/block/vold目录,挂载存储卡了其下有对应的节点信息 mkdir("/dev/block/vold", 0755); klog_set_level(6); // 初始化VolumeManager if (!(vm = VolumeManager::Instance())) { exit(1); } //单例模式获取NetlinkManager对象 if (!(nm = NetlinkManager::Instance())) { exit(1); } //设置是否打开VolumeManager中的日志,默认false if (android::base::GetBoolProperty("vold.debug", false)) { vm->setDebug(true); } //调用其start方法, if (vm->start()) { exit(1); } bool has_adoptable; bool has_quota; bool has_reserved; //解析fstab文件,该文件描述系统中各种文件系统的信息;我以MTK9669为例分析其fsab文件路径在vendor/etc/fstab.m7642 if (process_config(vm, &has_adoptable, &has_quota, &has_reserved)) { PLOG(ERROR) << "Water_x Error reading configuration... continuing anyways"; } //跟StorageManagerService通信 if (android::vold::VoldNativeService::start() != android::OK) { exit(1); } //调用NetlinkManagerstart方法 if (nm->start()) { exit(1); } //解析的参数设置到属性中 android::base::SetProperty("vold.has_adoptable", has_adoptable ? "1" : "0"); android::base::SetProperty("vold.has_quota", has_quota ? "1" : "0"); android::base::SetProperty("vold.has_reserved", has_reserved ? "1" : "0"); coldboot("/sys/block"); //将vold进程中主线程加入到线程池中 android::IPCThreadState::self()->joinThreadPool(); exit(0); }
这里主要做了如下核心工作:
初始化VolumeManager
初始化NetlinkManager
调用VolumeManager.start()
启动VoldNativeService::start() [跟StorageManagerService通信]
调用NetlinkManager.start()
下面就按照上面5个继续跟踪。
VolumeManager.cpp
通过单例模式初始化
Instance()
VolumeManager *VolumeManager::Instance() { if (!sInstance) sInstance = new VolumeManager(); return sInstance; }
VolumeManager()
VolumeManager::VolumeManager() { mDebug = false; mNextObbId = 0; mSecureKeyguardShowing = true; }
NetlinkManager.cpp
这个也是单例模式
Instance()
NetlinkManager *NetlinkManager::Instance() { if (!sInstance) sInstance = new NetlinkManager(); return sInstance; }
NetlinkManager()
NetlinkManager::NetlinkManager() { mBroadcaster = NULL; }
VolumeManager.cpp
start()
int VolumeManager::start() {
//清楚所有状态
unmountAll();
Devmapper::destroyAll();
Loop::destroyAll();
CHECK(mInternalEmulated == nullptr);
//创建/data/media的VolumeBase
mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>(
new android::vold::EmulatedVolume("/data/media"));
mInternalEmulated->create();
//更新虚拟磁盘
updateVirtualDisk();
return 0;
}
VoldNativeService.cpp
start()
status_t VoldNativeService::start() {
IPCThreadState::self()->disableBackgroundScheduling(true);
//publish就是把该服务公开,并添加到ServiceManager,可以让其他客户端查询
//具体看BinderService.h中publish()的定义
status_t ret = BinderService<VoldNativeService>::publish();
if (ret != android::OK) {
return ret;
}
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
ps->giveThreadPoolName();
return android::OK;
}
其中细节,具体看BinderService.h定定义哈
NetlinkManager.cpp
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;
//创建socket客户端
if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC,
NETLINK_KOBJECT_UEVENT)) < 0) {
return -1;
}
//设置网络套接字属性
if ((setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) &&
(setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0)) {
goto out;
}
if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
goto out;
}
//绑定服务端
if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
goto out;
}
//创建NetlinkHandler,并交给它处理通讯
mHandler = new NetlinkHandler(mSock);
//mHandler执行start()
if (mHandler->start()) {
goto out;
}
return 0;
out:
//关闭socket
close(mSock);
return -1;
}
这里主要
创建socket,并绑定
创建NetlinkHandler,并start()
NetlinkHandler.h
这个目录:system\vold\NetlinkHandler.h
class NetlinkHandler: public NetlinkListener {
public:
explicit NetlinkHandler(int listenerSocket);
virtual ~NetlinkHandler();
int start(void);
int stop(void);
protected:
virtual void onEvent(NetlinkEvent *evt);
};
NetlinkHandler.cpp
NetlinkHandler::NetlinkHandler(int listenerSocket) :
NetlinkListener(listenerSocket) {
}
NetlinkHandler::~NetlinkHandler() {
}
int NetlinkHandler::start() {
//调用其父类SocketListener中的方法,开始监听服务端中的消息
//消息会解析成NetlinkEvent对象作为参数并回调onEvent(NetlinkEvent *evt)方法
//NetlinkListener 的父类 SocketListener 类中的实现
return this->startListener();
}
int NetlinkHandler::stop() {
return this->stopListener();
}
// 获取到 kernel 事件 后调用这个函数进行处理
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
//这里获取VolumeManager
VolumeManager *vm = VolumeManager::Instance();
const char *subsys = evt->getSubsystem();
if (!subsys) {
return;
}
// 如果subsys是block类型的就调用VolumeManager的handleBlockEvent方法处理
if (std::string(subsys) == "block") {
vm->handleBlockEvent(evt);
}
}
这里会把kernel中事件上报到onEvent(),然后这里调用VolumeManager->handleBlockEvent()。
VolumeManager.cpp
handleBlockEvent()
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
//申请一个lock
std::lock_guard<std::mutex> lock(mLock);
//在事件属性参数中查找设备的路径;
std::string eventPath(evt->findParam("DEVPATH")?evt->findParam("DEVPATH"):"");
//在事件属性参数中查找设备的类型;
std::string devType(evt->findParam("DEVTYPE")?evt->findParam("DEVTYPE"):"");
//判断是否是“disk”类型,磁盘设备,否的话,直接返回不做任何处理
if (devType != "disk") return;
//上报的数据中获取主设备号;
int major = std::stoi(evt->findParam("MAJOR"));
//上报的数据中获取次设备号;
int minor = std::stoi(evt->findParam("MINOR"));
//makedev()作用是将主次设备号联合得到具体可访问的设备对象索引;
dev_t device = makedev(major, minor);
//判断事件的动作类型
switch (evt->getAction()) {
case NetlinkEvent::Action::kAdd: {
//循环判断mDiskSources,这个mDiskSources 在vold的main()函数时就已经配置好的。所以mDiskSources是固定的一些数据。
//在main()函数中调用了process_config()函数对VolumeManager::DiskSource进行赋值。具体是检索配置fstab文件,进行add操作。
for (const auto& source : mDiskSources) {
//从mDiskSources表获取的一个成员DiskSource类型的source,
//调用该成员的matches函数对 第11行获取的设备路径eventPath,进行匹配字符串比较。
if (source->matches(eventPath)) {
// For now, assume that MMC and virtio-blk (the latter is
// emulator-specific; see Disk.cpp for details) devices are SD,
// and that everything else is USB
int flags = source->getFlags();
//判断主设备号是否是mmc的设备;
if (major == kMajorBlockMmc
//判断是否是模拟器运行的;
|| (android::vold::IsRunningInEmulator()
//判断主设备号必须在 block设备范围内
&& major >= (int) kMajorBlockExperimentalMin
&& major <= (int) kMajorBlockExperimentalMax)) {
//将该磁盘Disk的flag标志为kSd
flags |= android::vold::Disk::Flags::kSd;
} else {
//将该磁盘Disk的flag标志为kUsb
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: {
handleDiskChanged(device);
break;
}
case NetlinkEvent::Action::kRemove: {
handleDiskRemoved(device);
break;
}
default: {
break;
}
}
}
这里是event事件处理中心,主要处理disk类型事件。
上面分别有三种状态
kAdd 挂载
kChange
kRemove 卸载
参考文章
《》
《》
《》
![[摘]Android SD卡挂载状态](https://www.biumall.com/wp-content/themes/BiuX/assets/images/random/0.webp)