目录
前言
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 Zygote进程的启动流程简单分析
前言在Android系统中,所有的应用程序进程以及系统服务进程SystemServer都是由Zygote进程孕育(fork)出来的,因为Android系统是基于Linux内核的,而在Linux系统中,所有的进程都是init进程的子孙进程,也就是说,所有的进程都是直接或者间接地由init进程for...
DisplayMetrics获取宽高不对
前言Android P项目开发时,获取的屏幕高度存在误差,之前项目中获取的高度都是固定的,后面为了适配各种项目,改为了动态获取屏幕高宽。记录于此,方便自己查阅。好记性不如烂笔头正文Android 版本 : Android P获取的屏幕高度错误adb shell wm size#打...
Android悬浮窗实现 使用WindowManager
WindowManager介绍通过Context.getSystemService(Context.WINDOW_SERVICE)可以获得 WindowManager对象。使用WindowManager可以在其他应用最上层,甚至手机桌面最上层显示窗口。调用的是WindowManager继承自...