Android vold介绍

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 checkpointing
    start 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:s0
    class core
    ioprio be 2
    writepid /dev/cpuset/foreground/tasks
    shutdown critical
    group 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:: handleMessage
    switch (msg.what) {
    
    
        .......
    case H_VOLUME_MOUNT: 
            final VolumeInfo vol = (VolumeInfo) msg.obj;
            mount(vol);
                 //通过binder向vm发送挂载命令,它将调用到VoldNativeService的mount
                 mVold.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机制

猜你喜欢

转载自blog.csdn.net/jasonactions/article/details/119651774