目录
- 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实例
-
VolumeManager模块负责管理所有挂载的设备节点以及相关操作的实际执行
-
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文件
- 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 {...};
};
- 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。
- 创建Socket,为PF_NETLINK类型
- 设置Socket的SO_RCVBUFFORCE(接受缓存区)小
设置Socket的SO_PASSCRED大小 - bind: 绑定socket
- 创建一个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机制