Android vold介绍

article/2025/10/2 20:31:10

目录

  • 1. 前言
  • 2. vold概述
  • 3. vold初始化
    • |- -vm->start()
    • |- -process_config
    • |- -hardware::configureRpcThreadpool
    • |- -vold::VoldNativeService::start
    • |- -nm->start()
  • 4. StorageManagerService
    • |- -SM与vold建立关联
      • |- - -startService(serviceClass)
    • |- -StorageManagerService的消息处理
  • 参考文档

1. 前言

本文主要是以内置存储设备的挂载为例来介绍vold的工作流程,首先会对vold做一个简单的介绍,然后会通过分析代码的方式来介绍内置存储的整个挂载流程。

2. vold概述

在这里插入图片描述

Vold(volume Daemon),即Volume守护进程,用来管理Android中存储类的热拔插事件,处于Kernel和Framework之间,是两个层级连接的桥梁。如上Vold在Android系统的整体架构。

Android的init进程会解析rc脚本,其中init.rc中定义了启动vold的部分

on early-fs# Once metadata has been mounted, we'll need vold to deal with userdata checkpointingstart vold

start vold最终被解析为启动vold服务,vold实际是一个守护进程,它直接由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:s0class coreioprio be 2writepid /dev/cpuset/foreground/tasksshutdown criticalgroup root reserved_disk

3. vold初始化

main(int argc, char** argv)|--VolumeManager* vm;|  NetlinkManager* nm;|--parse_args(argc, argv);|--mkdir("/dev/block/vold", 0755);|  //创建VolumeManager实例|--vm = VolumeManager::Instance()|  //创建NetlinkManager实例|--nm = NetlinkManager::Instance()|--android::base::GetBoolProperty("vold.debug", false)|--vm->start()|--process_config(vm, &has_adoptable, &has_quota, &has_reserved)|--android::hardware::configureRpcThreadpool(1, false /* callerWillJoin */);|--android::vold::VoldNativeService::start()|--nm->start()|--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");\--android::IPCThreadState::self()->joinThreadPool()

|- -vm->start()

VolumeManager::start()|  //start执行前卸载所有的文件系统|--unmountAll()|--Devmapper::destroyAll()|--Loop::destroyAll()|  //智能指针创建一个VolumeBase实例|--auto vol = std::shared_ptr<android::vold::VolumeBase>(|        new android::vold::EmulatedVolume("/data/media", 0));|--vol->setMountUserId(0)|  //调用VolumeBase的create方法|--vol->create()|      |--status_t res = doCreate();|  	   |--auto listener = getListener()|      \--listener->onVolumeCreated(getId(), static_cast<int32_t>(mType), |                    mDiskId, mPartGuid, mMountUserId);|--mInternalEmulatedVolumes.push_back(vol)\--updateVirtualDisk()

VolumeManager::start创建一个VolumeBase实例

  1. VolumeManager模块负责管理所有挂载的设备节点以及相关操作的实际执行

  2. vol->create(): 实际会调用父类VolumeBase的create函数,执行了doCreate以及回调了onVolumeCreated,此处的listener则是StorageMangerService服务,但是由于Vold启动较早,SystemServer还没有启动StorageMangerService,所以这里getListener()得到的是空,后面StorageMangerService启动完成后会重新触发

|- -process_config

process_config(vm, &has_adoptable, &has_quota, &has_reserved)|--ReadDefaultFstab(&fstab_default)|--for (auto& entry : fstab_default)if (entry.fs_mgr_flags.quota)*has_quota = true;if (entry.reserved_size > 0)*has_reserved = true;if (entry.fs_mgr_flags.vold_managed)if (entry.is_encryptable())flags |= android::vold::Disk::Flags::kAdoptable;*has_adoptable = true;if (entry.fs_mgr_flags.no_emulated_sd ||android::base::GetBoolProperty("vold.debug.default_primary", false))flags |= android::vold::Disk::Flags::kDefaultPrimary;vm->addDiskSource(std::shared_ptr<VolumeManager::DiskSource>(new VolumeManager::DiskSource(sysPattern, nickname, flags)))mDiskSources.push_back(diskSource)

process_config主要是用于解析fstab文件

  1. ReadDefaultFstab:将加载fstab文件,并与dts中的fstab进行合并,最终保存到fstab_default,这其中主要遍历几个fstab的位置,包括:/etc/recovery.fstab,/odm/etc/fstab., /vendor/etc/fstab., /fstab.,我们的方案中实际会使用/vendor/etc/fstab.
    fstab_default是Fstab类型,即std::vector,fstab文件最终解析结果会存放到fstab_default
    我们可以看到FstabEntry的结构如下,它用于保存fstab中的一条记录
struct FstabEntry {std::string blk_device;std::string logical_partition_name;std::string mount_point;std::string fs_type;unsigned long flags = 0;std::string fs_options;std::string fs_checkpoint_opts;std::string key_loc;std::string metadata_key_dir;std::string metadata_encryption;off64_t length = 0;std::string label;int partnum = -1;int swap_prio = -1;int max_comp_streams = 0;off64_t zram_size = 0;off64_t reserved_size = 0;std::string encryption_options;off64_t erase_blk_size = 0;off64_t logical_blk_size = 0;std::string sysfs_path;std::string vbmeta_partition;uint64_t zram_backingdev_size = 0;std::string avb_keys;struct FsMgrFlags {...};
};
  1. for循环将遍历fstab中被解析的每一条记录,为每条记录创建DiskSource,通过vm->addDiskSource存放到mDiskSources

|- -hardware::configureRpcThreadpool

TODO

|- -vold::VoldNativeService::start

android::vold::VoldNativeService::start()|--IPCThreadState::self()->disableBackgroundScheduling(true)|  //此处会获取serviceManager并通过addService添加服务|--BinderService<VoldNativeService>::publish()|      |--sp<IServiceManager> sm(defaultServiceManager());|      \--sm->addService(String16(SERVICE::getServiceName()), |              new SERVICE(), allowIsolated, dumpFlags)|--sp<ProcessState> ps(ProcessState::self());|--ps->startThreadPool();\--ps->giveThreadPoolName()\--androidSetThreadName( makeBinderThreadName().string() )

VoldNativeService继承自BinderService,start主要注册了接口,使其他服务可以通过IVold可以找到,然后启动线程,它主要用于与SM通信

publish:此处会获取serviceManager并通过addService添加服务

ProcessState::self:创建按ProcessState单例,并会在binder驱动中创建binder_pro。ProcessState的单例模式的惟一性,因此一个进程只打开binder设备一次,其中ProcessState的成员变量mDriverFD记录binder驱动的fd,用于访问binder设备。ProcessState是负责打开Binder节点并做mmap映射,IPCThreadState是负责与Binder驱动进行具体的命令交互。

ps->startThreadPool:startThreadPool主要是通过创建线程池,实际只创建了一个线程,最终执行joinThreadPool,通过循环调用getAndExecuteCommand->talkWithDriver来与binder驱动进行交互。

|- -nm->start()

nm->start()    |--socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT)|--setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) |--setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz))|--setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))|--bind(mSock, (struct sockaddr*)&nladdr, sizeof(nladdr))|--mHandler = new NetlinkHandler(mSock)\--mHandler->start()

start函数内部建立了一个socket连接,用于接收所有的uevent事件,最后会new一个NetlinkHandler对象,并执行start函数,然后会调用NetlinkListener父类的startListener函数去监听event。

  1. 创建Socket,为PF_NETLINK类型
  2. 设置Socket的SO_RCVBUFFORCE(接受缓存区)小
    设置Socket的SO_PASSCRED大小
  3. bind: 绑定socket
  4. 创建一个NetlinkHandler对象,并启动它
    NetlinkManager 路径: system/vold/NetlinkManager.cpp
mHandler->start()\--SocketListener::startListener()|--mSock = android_get_control_socket(mSocketName)|--listen(mSock, backlog)|--pipe2(mCtrlPipe, O_CLOEXEC)\--pthread_create(&mThread, nullptr, SocketListener::threadStart, this)|--SocketListener *me = reinterpret_cast<SocketListener *>(obj)|--me->runListener()|--while (true)onDataAvailable(c)

NetlinkHandler继承自NetlinkListener,NetlinkListener又是SoctetListener的子类,因此最终还是调用SoctetListener的startListener函数。该函数就是开始监听消息,接着启动一个线程执行runListener函数,循环读取socket消息并发送给各个client端,NetlinkListener作为其中一个,收到Callback后则会去进一步处理。

NetlinkListener::onDataAvailable(SocketClient *cli)|--int socket = cli->getSocket();|--NetlinkEvent *evt = new NetlinkEvent();\--if (evt->decode(mBuffer, count, mFormat))onEvent(evt);|--VolumeManager* vm = VolumeManager::Instance();|--if (std::string(subsys) == "block")vm->handleBlockEvent(evt)

onDataAvailable这边是来真正接收数据的,通过给到的client字段与之建立socket通信,借助uevent_kernel_recv函数读取数据,通过decode解析后调用onEvent分发下去。这时候NetlinkHandler就登场了,获取VolumeManager单例对象,调用handleBlockEvent进行事件真正的处理。

到这里Vold的启动过程基本就结束了,后续Vold会监听kernel的uevent事件,然后处理转发通过Callback通知到SM,而Framework的服务以及App则可以通过SM去使用Vold处理Command。
上半部分介绍了Kernel和Vold之间的联系,下面来看下SM和Vold之间的联系

以内置存储为例,讲述处理过程:

void VolumeManager::handleBlockEvent(NetlinkEvent* evt)|--switch (evt->getAction()) {case NetlinkEvent::Action::kAdd: auto disk = new android::vold::Disk(eventPath, device, source->getNickname(), flags);handleDiskAdded(std::shared_ptr<android::vold::Disk>(disk));|--disk->create()|--auto listener = VolumeManager::Instance()->getListener();|  //会调用到SMS的onDiskCreated|--if (listener) listener->onDiskCreated(getId(), mFlags);|--readMetadata();|--readPartitions();break;...

此处的listener则是StorageMangerService服务,但是由于Vold启动较早,SystemServer还没有启动StorageMangerService,所以这里getListener()得到的是空,后面StorageMangerService启动完成后会重新触发

4. StorageManagerService

|- -SM与vold建立关联

private void startOtherServices(@NonNull TimingsTraceAndSlog t)|--.....|--mSystemServiceManager.startService(STORAGE_MANAGER_SERVICE_CLASS);|     |--final Class<SystemService> serviceClass = |     |       loadClassFromLoader(STORAGE_MANAGER_SERVICE_CLASS,|     |              this.getClass().getClassLoader());|     \--startService(serviceClass)|--storageManager = IStorageManager.Stub.asInterface(|                        ServiceManager.getService("mount"));|--.....

SystemServer中会通过SystemServiceManager.startService(STORAGE_STATS_SERVICE_CLASS)来启动此服务
通过ServiceManager.getService(“mount”)获取服务,

|- - -startService(serviceClass)

startService(serviceClass)|--mServices.add(STORAGE_MANAGER_SERVICE_CLASS)|--STORAGE_MANAGER_SERVICE_CLASS.onStart()| //创建StorageManagerService|--mStorageManagerService = new StorageManagerService(getContext())|  //将StorageManagerService注册到ServiceManager中|--publishBinderService("mount", mStorageManagerService);|  //调用StorageManagerService的start方法|--mStorageManagerService.start();| //StorageManagerService和Vold进程启动并建立和通信|--connectStoraged()|    |--IBinder binder = ServiceManager.getService("storaged")|    |  //通过binder机制,获取mVold对象(mVold就是IVold对象,这是|    |  //一个代理类,具体实现在VoldNativeService.cpp),从而和|    |  //Vold进程进行通信.|    |--mStoraged = IStoraged.Stub.asInterface(binder)|--connectVold()|--binder = ServiceManager.getService("vold")|--mVold = IVold.Stub.asInterface(binder)|  //mListener是IVoldListener的具体实现, 对应便是|  //VoldNativeService这个接口类,当vold进程中相关事件改|  //变通过IVoldListener这个代理,通知|  //StorageManagerService处理.|--mVold.setListener(mListener)

在StorageManagerService中,当SystemServer启动StorageManagerService时候,回调onStart方法,然后会通过binder获得IVold接口,并且将mListener注册过去,这里便是Vold的aidl接口,对应便是VoldNativeService这个接口类,这样就建立了StorageManagerService与vold链接

|- -StorageManagerService的消息处理

StorageManagerServiceHandler:: handleMessage(Message msg)switch (msg.what) {......case H_BOOT_COMPLETED: {handleBootCompleted();|--initIfBootedAndConnected();|--resetIfBootedAndConnected()......}
private void handleBootCompleted()|--initIfBootedAndConnected()|--resetIfBootedAndConnected()

AMS的finishBooting函数中通过SystemProperties.set(“sys.boot_completed”, “1”);设置boot_completed属性为1

private void resetIfBootedAndConnected()|--mVold.reset();|--translate(VolumeManager::Instance()->reset())|--for (const auto& disk : mDisks)disk->destroy();disk->create();|  //此处的listener 就是StorageManagerService|--auto listener = VolumeManager::Instance()->getListener();|  //通过binder通信回调StorageManagerService|--if (listener) listener->onDiskCreated(getId(), mFlags)  |--readMetadata();|--readPartitions();           

当开机广播BootCompleted发出后?,SM则会进行lockuser或者unlockuser的操作,接着会添加内置存储,并且reset Vold,其实对应的是调用VM的reset函数,最后是start user,创建对应文件目录,链接到对应的data存储分区。

这里来看一下reset的过程,因为前面VM启动过程中,mInternalEmulated->create()会调用getListener()获取监听方法,但是彼时SystemServer还没有启动,SM还没有注册下来,所以并没有通知上去

此处SM启动结束后执行reset,就会重新执行disk->create();过程,这样就会通知到SM,触发InternalEmulated去mount。

onVolumeCreatedLocked(vol)|--if (vol.type == VolumeInfo.TYPE_EMULATED)设置挂载参数mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();else if (vol.type == VolumeInfo.TYPE_PUBLIC)设置挂载参数mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget()else if (vol.type == VolumeInfo.TYPE_PRIVATE)mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();else if (vol.type == VolumeInfo.TYPE_STUB)vol.mountUserId = mCurrentUserId;mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget()

之后StorageManagerServiceHandler:: handleMessage将处理H_VOLUME_MOUNT消息

StorageManagerServiceHandler:: handleMessageswitch (msg.what) {.......case H_VOLUME_MOUNT: final VolumeInfo vol = (VolumeInfo) msg.obj;mount(vol);//通过binder向vm发送挂载命令,它将调用到VoldNativeService的mountmVold.mount(vol.id, vol.mountFlags, vol.mountUserId);......}

上面便是Kernel和Vold以及SM和Vold之间的联系,以及他们之间是如何进行交互。前者是通过监听Kernel uevent事件来完成上报,后者是通过binder建立通信,通过binder由SM向Vold发送命令,并且在Vold注册listener完成消息上报。

如上为system_server重启的reset执行流程

参考文档

Android Vold简介(一)
https://www.jianshu.com/p/e0c583ea9289
https://blog.51cto.com/u_4526621/1335159
https://blog.csdn.net/vnanyesheshou/article/details/79047650

一篇文章了解相见恨晚的 Android Binder 进程间通讯机制

设计模式:代理(Proxy)模式

3分钟带你看懂android中的Binder机制


http://chatgpt.dhexx.cn/article/Z0wgZcEb.shtml

相关文章

<Android开发> Android vold - 第一篇 vold前言简介

本系列主要介绍 Android vold&#xff0c;分为以下篇章 &#xff1c;Android开发&#xff1e; Android vold - 第一篇 vold前言简介 &#xff1c;Android开发&#xff1e; Android vold - 第二篇 vold 的main()函数简介 &#xff1c;Android开发&#xff1e; Android vold - 第…

Vold原理介绍

一、 Vold简介 Android中Vold是volume Daemon&#xff0c;即Volume守护进程&#xff0c;用来管理Android中存储类的热拔插事件。这里的热插拔涉及的场景如&#xff1a; 1. 手机usb以MTP或者传输照片方式插拔PC端后磁盘数据的挂卸载&#xff1b; 2. 设备开关机过程中存储设备各分…

C语言Switch....case用法

概述 C语言switch语句通常用于多个条件判断&#xff0c;根据不同情况执行不同的代码块。它的使用形式如下&#xff1a; switch&#xff08;表达式&#xff09; { case 常量表达式1&#xff1a; 语句序列1 break; case 常量表达式2&#xff1a; 语句序列2 break; ...... default…

MySQL 入门:Case 语句很好用

引言 MySQL CASE 是一个 MySQL 语句查询关键字&#xff0c;它定义了处理循环概念以执行条件集并使用 IF ELSE 返回匹配案例的方式。 MySQL 中的 CASE 是一种控制语句&#xff0c;它验证条件案例集&#xff0c;并在第一个案例满足 else 值时显示值并退出循环。 如果没有找到 T…

Shell 编程之 case 语句

一、case 语句 1、case 语句概述 (1)case 语句的作用 使用 case 语句改写 if 多分支可以使脚本结构更加清晰、层次分明。针对变量的不同取 值&#xff0c;执行不同的命令序列。 2、case 语句的结构: case 变量值 in 模式 1) 命令序列 1 ;; 模式 2) 命令序列 2 ;; *…

【shell】case实现简单的系统工具箱

case实现简单的系统工具箱 case实现简单的系统工具箱 #!/usr/bin/bash #system manage #by racon 2020-04-19menu() {cat <<-EOF########################################## h. help ## f. disk partition ## d. filesystem mount ## m. memory ## u. system lo…

SQL CASE语句的使用

SQL CASE语句的使用 CASE是一个控制流语句&#xff0c;其作用与IF-THEN-ELSE语句非常相似&#xff0c;可根据数据选择值。 CASE语句遍历条件并在满足第一个条件时返回值。 因此&#xff0c;一旦条件成立&#xff0c;它将短路&#xff0c;从而忽略后面的子句并返回结果。 正如我…

数据库 case 用法

【转载】:数据库中case when 的用法 CASE WHEN 及 SELECT CASE WHEN的用法Case具有两种格式。简单Case函数和Case搜索函数。 1.简单Case函数 CASE sex WHEN 1 THEN 男 WHEN 2 THEN 女 ELSE 其他 END 2.Case搜索函数 CASE WHEN sex 1 THEN 男 WHEN sex 2 THEN 女 ELSE 其他 …

SQL之CASE WHEN用法详解

简单CASE WHEN函数&#xff1a; CASE SCORE WHEN A THEN 优 ELSE 不及格 END CASE SCORE WHEN B THEN 良 ELSE 不及格 END CASE SCORE WHEN C THEN 中 ELSE 不及格 END 等同于&#xff0c;使用CASE WHEN条件表达式函数实现&#xff1a; CASE WHEN SCORE A THEN 优WHEN SCORE…

switch case语法

文章目录 switch case组合不要拿青龙偃月刀去削苹果case的作用是什么&#xff1f;break的作用是什么&#xff1f;case后面的值有什么要求吗&#xff1f;case语句的排列顺序问题default语句相关问题使用case语句的一些注意事项 switch case组合 基本语法结构 switch(整型常量/…

SQL中case的使用方法

Case具有两种格式。简单Case函数和Case搜索函数。 1.简单Case函数 CASE sex WHEN 1 THEN 男WHEN 2 THEN 女 ELSE 其他 END2.Case搜索函数 CASE WHEN sex 1 THEN 男WHEN sex 2 THEN 女ELSE 其他 END3.简单case函数 VS case搜索函数 这两种方式&#xff0c;可以实现相同的功…

[转载]常用CASE工具介绍

[转载]常用CASE工具介绍转载自&#xff1a;http://www.cnblogs.com/powerlc/archive/2006/01/12/315959.html 一&#xff0c;概述 今天, 代码变得日益简单, 在Model的指导下, 思想, 设计, 分析都变得异常重要。企业业务建模工具, 产品非常多, 特别是在MDA日益流行的今天. Work…

CASE语句的使用方法

CASE语句有两种&#xff1a; 一种是case [column] when&#xff0c;指定了判断条件所在的列。 另一种是case when [column]&#xff0c;因为条件在子句中所以能对任意列进行判断。 本例建立一个员工表&#xff0c;有员工id&#xff08;id&#xff09;&#xff0c;员工姓名&am…

常用CASE工具介绍 ZZ

常用CASE工具介绍 一&#xff0c;概述  今天, 代码变得日益简单, 在Model的指导下, 思想, 设计, 分析都变得异常重要。企业业务建模工具, 产品非常多, 特别是在MDA日益流行的今天. WorkFlow是典型的业务及流程建模。 二&#xff0c;软件开发CASE工具简介   (一)图稿绘制&…

CASE 工具有哪些

CASE 工具 CASE工具设置的软件应用程序。这使用为自动的SDLC活动。 CASE工具所使用的软件项目经理,分析师和工程师开发的软件系统. 有许多CASE工具做软件开发生命周期的各个阶段,如工具,设计工具,项目管理工具,数据库管理工具,文档工具分析. 为了得到所需的结果,CASE工具…

网络:简述路由算法之动态路由算法

网络&#xff1a;简述路由算法之动态路由算法 在计算机网络中&#xff0c;路由器的一个很重要责任就是要在端对端的节点中找出一条最佳路径出来&#xff0c;通过自己与相邻节点之间的信息&#xff0c;来计算出从自己位置到目的节点之间的最佳线路&#xff0c;这种算法我们可以理…

路由选择算法——链路状态算法

好久没写东西了&#xff0c;好生疏的感觉。。 链路状态算法 这是一种全局式的路由选择算法&#xff0c;也就是说&#xff0c;一个路由器知道到其他路由器的所有链路的状态信息&#xff08;例如某条链路上堵不堵&#xff09;&#xff0c;并且假设这种信息是被量化好了的&#…

示例演示“距离矢量路由算法”工作原理

以下内容摘自刚刚上市&#xff0c;已被纳入全国高校教材系统&#xff0c;并在全国热销、好评如潮的《深入理解计算机网络》新书。 7.5.3 距离矢量路由算法 现代计算机网络通常使用动态路由算法&#xff0c;因为这类算法能够适应网络的拓扑和流量变化&#xff0c;其中最流行的…

距离矢量路由算法

现代计算机网络通常使用动态路由算法&#xff0c;因为这类算法能够适应网络的拓扑和流量变化&#xff0c;其中最流行的两种动态路由算法是“距离矢量路由算法”和“链路状态路由算法”。 距离矢量路由算法&#xff08;Distance Vector Routing&#xff0c;DV&#xff09;是ARPA…

路由算法之距离矢量算法和链路状态算法

我们之前说了&#xff0c;路由器需要对于每一对端端节点都要寻找出一个最佳的路径&#xff0c;比如说最小链路成本的路径。路由算法就是通过自己到相邻节点之间的信息来计算出自己到目的地址的最佳出境线路是哪一条&#xff0c;进而进行转发的一类算法。具有代表性的就是距离矢…