目录
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实例
-
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:: 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