Vold: Volume Daemon,用于管理和控制Android平台外部存储设备的后台进程,这些管理和控制,包括SD卡的插拔事件检测/SD卡挂载/卸载/格式化等.

9.0以前framework java层(StorageManagerService)和native层(Vold)的通信是socket,9.0以后使用binder通信.本文通过SD卡挂载流程,分析binder在vold服务中的使用.

vold服务在开机的时候会启动.定义于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:s0class coreioprio be 2writepid /dev/cpuset/foreground/tasksshutdown criticalgroup reserved_disk

被init进程启动后,将调用system/vold/main.cpp中的main函数,然后初始化VolumeManager,NetlinkManager等等.初始化Vold服务.

在看下StorageManagerService的初始化.StorageManagerService由SystemServer启动,我们简单看看它的启动流程:

//调用SystemServiceManager的startService
mSystemServiceManager.startService(STORAGE_MANAGER_SERVICE_CLASS);最终的实现如下:
public void startService(@NonNull final SystemService service) {// Register it.mServices.add(service);// Start it.long time = SystemClock.elapsedRealtime();try {//调用服务的onStart方法.service.onStart();} catch (RuntimeException ex) {throw new RuntimeException("Failed to start service " + service.getClass().getName()+ ": onStart threw an exception", ex);}warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");}//StorageManagerService的onStart方法如下:@Overridepublic void onStart() {//创建StorageManagerServicemStorageManagerService = new StorageManagerService(getContext());//将StorageManagerService注册到ServiceManager中publishBinderService("mount", mStorageManagerService);//调用StorageManagerService的start方法mStorageManagerService.start();}private void start() {connect();}//主要建立和Vold的通信,获取mVold对象,与Vold进程通信.private void connect() {IBinder binder = ServiceManager.getService("storaged");if (binder != null) {try {//为binder对象设置死亡代理。当binder死亡后重新建立连接.binder.linkToDeath(new DeathRecipient() {@Overridepublic void binderDied() {Slog.w(TAG, "storaged died; reconnecting");mStoraged = null;connect();}}, 0);} catch (RemoteException e) {binder = null;}}if (binder != null) {mStoraged = IStoraged.Stub.asInterface(binder);} else {Slog.w(TAG, "storaged not found; trying again");}binder = ServiceManager.getService("vold");if (binder != null) {try {//为binder对象设置死亡代理。当binder死亡后重新建立连接.binder.linkToDeath(new DeathRecipient() {@Overridepublic void binderDied() {Slog.w(TAG, "vold died; reconnecting");mVold = null;connect();}}, 0);} catch (RemoteException e) {binder = null;}}if (binder != null) {//通过binder机制,获取mVold对象(mVold就是IVold对象,这是一个代理类,具体实现在VoldNativeService.cpp),从而和Vold进程进行通信.mVold = IVold.Stub.asInterface(binder);try {//mListener是IVoldListener的具体实现,当vold进程中相关事件改变通过IVoldListener这个代理,通知StorageManagerService处理.mVold.setListener(mListener);} catch (RemoteException e) {mVold = null;Slog.w(TAG, "vold listener rejected; trying again", e);}} else {Slog.w(TAG, "vold not found; trying again");}if (mStoraged == null || mVold == null) {BackgroundThread.getHandler().postDelayed(() -> {connect();}, DateUtils.SECOND_IN_MILLIS);} else {onDaemonConnected();}}至此,StorageManagerService和Vold进程启动并建立和通信.

在Android9.0:/system/vold/binder/android/os/路径下多了如下几个文件,用于binder通信,关于binder通信就不在过多介绍,网上有很多优秀的资料,大家可以查找阅读.
IVold.aidl    
IVoldListener.aidl    
IVoldTaskListener.aidl

说下VoldNativeService.cpp这个文件,是IVold的具体实现.例如当mVold这个代理对象去调用mount方法,通过binder机制最终调用到VoldNativeService的mount方法.从而实现跨进程通信,有兴趣的同学可以自己研究下中间调用过程这里不在叙述.

下面说下9.0上SD卡的挂载流程.

先来一张9.0SD卡挂载流程图:

我们知道Vold服务初始化的时候执行main函数,会初始化NetlinkManager,执行start方法,其中会创建一个NetlinkHandler,当底层Kernel发送消息Uevent,经过一系列处理,最终调用VolumeManager的handleBlockEvent处理消息.
其实NetlinkManager启动后就是创建一个可以接收Kernel消息的socket,并以此socket构建并启动NetlinkHandler。 
可以预见NetlinkHandler将用来处理socket收到的信息。

void NetlinkHandler::onEvent(NetlinkEvent *evt) {VolumeManager *vm = VolumeManager::Instance();//判断当前的Uevent消息是什么类型const char *subsys = evt->getSubsystem();if (!subsys) {LOG(WARNING) << "No subsystem found in netlink event";return;}//如果subsys类型是块设备,就调用handleBlockEvent处理该消息if (std::string(subsys) == "block") {vm->handleBlockEvent(evt);}
}
下面vold服务开始真正处理SD卡挂载流程.
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {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"):"");//设备Type不为disk就返回if (devType != "disk") return;//major和minor分别表示该设备的主次设备号,二者联合起来可以识别一个设备.int major = std::stoi(evt->findParam("MAJOR"));int minor = std::stoi(evt->findParam("MINOR"));dev_t device = makedev(major, minor);switch (evt->getAction()) {case NetlinkEvent::Action::kAdd: {for (const auto& source : mDiskSources) {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 USBint flags = source->getFlags();if (major == kMajorBlockMmc|| (android::vold::IsRunningInEmulator()&& major >= (int) kMajorBlockExperimentalMin&& major <= (int) kMajorBlockExperimentalMax)) {flags |= android::vold::Disk::Flags::kSd;} else {flags |= android::vold::Disk::Flags::kUsb;}//新建一个Disk,用来保存当前磁盘信息.auto disk = new android::vold::Disk(eventPath, device,source->getNickname(), flags);handleDiskAdded(std::shared_ptr<android::vold::Disk>(disk));break;}}break;}...
}
//处理磁盘插入,主要调用Disk.cpp的create方法.初始化Disk.
void VolumeManager::handleDiskAdded(const std::shared_ptr<android::vold::Disk>& disk) {// For security reasons, if secure keyguard is showing, wait// until the user unlocks the device to actually touch itif (mSecureKeyguardShowing) {LOG(INFO) << "Found disk at " << disk->getEventPath()<< " but delaying scan due to secure keyguard";mPendingDisks.push_back(disk);} else {disk->create();mDisks.push_back(disk);}
}   status_t Disk::create() {CHECK(!mCreated);mCreated = true;//onDiskCreated,通过binder机制,通知StorageManagerService磁盘创建auto listener = VolumeManager::Instance()->getListener();if (listener) listener->onDiskCreated(getId(), mFlags);//检查文件系统格式和读取文件分区列表.readMetadata();readPartitions();
...return OK;
}status_t Disk::readPartitions() {...Table table = Table::kUnknown;bool foundParts = false;for (const auto& line : output) {auto split = android::base::Split(line, kSgdiskToken);auto it = split.begin();if (it == split.end()) continue;if (*it == "DISK") {if (++it == split.end()) continue;if (*it == "mbr") {table = Table::kMbr;} else if (*it == "gpt") {table = Table::kGpt;} else {LOG(WARNING) << "Invalid partition table " << *it;continue;}} else if (*it == "PART") {foundParts = true;if (++it == split.end()) continue;int i = 0;if (!android::base::ParseInt(*it, &i, 1, maxMinors)) {LOG(WARNING) << "Invalid partition number " << *it;continue;}dev_t partDevice = makedev(major(mDevice), minor(mDevice) + i);if (table == Table::kMbr) {if (++it == split.end()) continue;int type = 0;if (!android::base::ParseInt("0x" + *it, &type)) {LOG(WARNING) << "Invalid partition type " << *it;continue;}switch (type) {case 0x06:  // FAT16case 0x07:  // HPFS/NTFS/exFATcase 0x0b:  // W95 FAT32 (LBA)case 0x0c:  // W95 FAT32 (LBA)case 0x0e:  // W95 FAT16 (LBA)//创建SD卡的volume信息createPublicVolume(partDevice);break;}} ...
}void Disk::createPublicVolume(dev_t device) {auto vol = std::shared_ptr<VolumeBase>(new PublicVolume(device));//如果只是分区的创建,走进判断里.if (mJustPartitioned) {LOG(DEBUG) << "Device just partitioned; silently formatting";vol->setSilent(true);vol->create();vol->format("auto");vol->destroy();vol->setSilent(false);}mVolumes.push_back(vol);vol->setDiskId(getId());//调用VolumeBase的create方法.由于PublicVolume是VolumeBase的子类,且具体实现VolumeBase的方法,这里其实调用的是PublicVolume的doCreate方法.vol->create();
}status_t VolumeBase::create() {CHECK(!mCreated);mCreated = true;status_t res = doCreate();auto listener = getListener();//onVolumeCreated,通过binder机制,通知StorageManagerService创建volumeif (listener) listener->onVolumeCreated(getId(),static_cast<int32_t>(mType), mDiskId, mPartGuid);setState(State::kUnmounted);return res;
}//这里走进了StorageManagerService,@Overridepublic void onVolumeCreated(String volId, int type, String diskId, String partGuid) {synchronized (mLock) {final DiskInfo disk = mDisks.get(diskId);//保存Volume的信息到VolumeInfofinal VolumeInfo vol = new VolumeInfo(volId, type, disk, partGuid);mVolumes.put(volId, vol);onVolumeCreatedLocked(vol);}}@GuardedBy("mLock")private void onVolumeCreatedLocked(VolumeInfo vol) {//这里主要根据设备类型,设置挂载的Flag,最终通过handler发送挂载信息....vol.mountUserId = mCurrentUserId;mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();} else if (vol.type == VolumeInfo.TYPE_PRIVATE) {mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();} else {Slog.d(TAG, "Skipping automatic mounting of " + vol);}}lass StorageManagerServiceHandler extends Handler {public StorageManagerServiceHandler(Looper looper) {super(looper);}@Overridepublic void handleMessage(Message msg) {....case H_VOLUME_MOUNT: {final VolumeInfo vol = (VolumeInfo) msg.obj;if (isMountDisallowed(vol)) {Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");break;}try {slogi(TAG, "Cmd send volume mount from handler " + vol.id + " "+ vol.mountFlags + " " + vol.mountUserId);//发送挂载命令,mVold.mount(vol.id, vol.mountFlags, vol.mountUserId);slogi(TAG, "Cmd send volume mount from handler end " + vol.id + " "+ vol.mountFlags + " " + vol.mountUserId);} catch (Exception e) {Slog.wtf(TAG, e);}break;}
}mVold.mount在VoldNativeService中处理.
binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountFlags,int32_t mountUserId) {ENFORCE_UID(AID_SYSTEM);CHECK_ARGUMENT_ID(volId);ACQUIRE_LOCK;auto vol = VolumeManager::Instance()->findVolume(volId);if (vol == nullptr) {return error("Failed to find volume " + volId);}vol->setMountFlags(mountFlags);vol->setMountUserId(mountUserId);//调用VolumeBase的mount.int res = vol->mount();if ((mountFlags & MOUNT_FLAG_PRIMARY) != 0) {VolumeManager::Instance()->setPrimary(vol);}return translate(res);
}status_t VolumeBase::mount() {if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) {LOG(WARNING) << getId() << " mount requires state unmounted or unmountable";return -EBUSY;}//设置当前状态为checkingsetState(State::kChecking);//调用子类PublicVolume的doMount方法.status_t res = doMount();if (res == OK) {//设置挂载成功状态,向上通知onVolumeStateChanged.setState(State::kMounted);} else {setState(State::kUnmountable);}return res;
}//实现挂载,doMount函数做了大量工作,由于自己水平有限,这里面很多调用还摸不清,如有大神知道,请指点指点,后续我了解了也会更新上来.
status_t PublicVolume::doMount() {readMetadata();//查看SD卡是否为vfat格式,系统是否支持.if (mFsType == "vfat" && vfat::IsSupported()) {//调用文件系统check函数检查是否是vfat格式.if (vfat::Check(mDevPath)) {LOG(ERROR) << getId() << " failed filesystem check";return -EIO;}} else if (mFsType == "exfat" && exfat::IsSupported()) {if (exfat::Check(mDevPath)) {LOG(ERROR) << getId() << " failed filesystem check";return -EIO;}} else {LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;return -EIO;}// Use UUID as stable name, if availablestd::string stableName = getId();if (!mFsUuid.empty()) {stableName = mFsUuid;}mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str());mFuseDefault = StringPrintf("/mnt/runtime/default/%s", stableName.c_str());mFuseRead = StringPrintf("/mnt/runtime/read/%s", stableName.c_str());mFuseWrite = StringPrintf("/mnt/runtime/write/%s", stableName.c_str());setInternalPath(mRawPath);if (getMountFlags() & MountFlags::kVisible) {setPath(StringPrintf("/storage/%s", stableName.c_str()));} else {setPath(mRawPath);}if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT)) {PLOG(ERROR) << getId() << " failed to create mount points";return -errno;}if (mFsType == "vfat") {//将设备节点挂载在mRawPath下.if (vfat::Mount(mDevPath, mRawPath, false, false, false, AID_MEDIA_RW, AID_MEDIA_RW, 0007,true)) {PLOG(ERROR) << getId() << " failed to mount " << mDevPath;return -EIO;}} else if (mFsType == "exfat") {if (exfat::Mount(mDevPath, mRawPath, AID_MEDIA_RW, AID_MEDIA_RW, 0007)) {PLOG(ERROR) << getId() << " failed to mount " << mDevPath;return -EIO;}}if (getMountFlags() & MountFlags::kPrimary) {initAsecStage();}if (!(getMountFlags() & MountFlags::kVisible)) {// Not visible to apps, so no need to spin up FUSEreturn OK;}if (fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||fs_prepare_dir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT)) {PLOG(ERROR) << getId() << " failed to create FUSE mount points";return -errno;}dev_t before = GetDevice(mFuseWrite);if (!(mFusePid = fork())) {if (getMountFlags() & MountFlags::kPrimary) {if (execl(kFusePath, kFusePath,"-u", "1023", // AID_MEDIA_RW"-g", "1023", // AID_MEDIA_RW"-U", std::to_string(getMountUserId()).c_str(),"-w",mRawPath.c_str(),stableName.c_str(),NULL)) {PLOG(ERROR) << "Failed to exec";}} else {if (execl(kFusePath, kFusePath,"-u", "1023", // AID_MEDIA_RW"-g", "1023", // AID_MEDIA_RW"-U", std::to_string(getMountUserId()).c_str(),mRawPath.c_str(),stableName.c_str(),NULL)) {PLOG(ERROR) << "Failed to exec";}}LOG(ERROR) << "FUSE exiting";_exit(1);}if (mFusePid == -1) {PLOG(ERROR) << getId() << " failed to fork";return -errno;}nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);while (before == GetDevice(mFuseWrite)) {LOG(VERBOSE) << "Waiting for FUSE to spin up...";usleep(50000); // 50msnsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME);if (nanoseconds_to_milliseconds(now - start) > 5000) {LOG(WARNING) << "Timed out while waiting for FUSE to spin up";return -ETIMEDOUT;}}/* sdcardfs will have exited already. FUSE will still be running */if (TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, WNOHANG)) == mFusePid)mFusePid = 0;return OK;
}

参考:
http://blog.csdn.net/gaugamela/article https://blog.csdn.net/Gaugamela/article/details/52484058
邓平凡大神的<深入理解Android卷1>第九章 vold的原理与机制分析

Android9.0版本Vold服务源码分析相关推荐

  1. Android9.0版本Vold服务源码分析之上层处理SD卡挂载

    本文接上一篇SD卡挂载之后,上层处理,主要是创建通知,提示用户.涉及 xref: /frameworks/base/services/core/java/com/android/server/Stor ...

  2. android6.0源码分析之AMS服务源码分析

    activitymanagerservice服务源码分析 1.ActivityManagerService概述 ActivityManagerService(以下简称AMS)作为Android中最核心 ...

  3. Netty网络框架学习笔记-16(心跳(heartbeat)服务源码分析)

    Netty网络框架学习笔记-16(心跳(heartbeat)服务源码分析_2020.06.25) 前言: Netty 作为一个网络框架,提供了诸多功能,比如编码解码等,Netty 还提供了非常重要的一 ...

  4. 【esp32-adf】按键服务源码分析

    一.adc按键 二.源码分析 2.1 数据结构 设备集合 typedef struct esp_periph_sets {EventGroupHandle_t state_event_bits;xSe ...

  5. [导入]SunriseUpload.0.9.1的源码分析(七)

    接着分析了几个小时的SunriseUpload.0.9.1的源码. 终于明白了作者的整体思路.在此就做一个总结. 首先,要想能上传很大的文件,我们就必须编写一个HttpModule来自己处理用户上传的 ...

  6. WinCE6.0学习之EBoot源码分析----startup.s(三)

    下面将详细叙述MMU的设置,也是本人花费时间最多的一部分内容,无论是2410.6410甚至是Cortex-A8核的ARM,MMU的设置基本都一样,所以移植时这部分可以直接搬过来,只需要更改全局内存映射 ...

  7. tensorflow 2.0 Layer定义的源码分析

    一直不太懂tensorflow 2.0的层的操作,所以跑去看了下源码,其实也不难,如果对python比较了解的话,自己去看下源码也很快就能理解了. tensorflow 2.0中的api都是使用了ke ...

  8. 基于Android5.0的Camera Framework源码分析 (三)

    上一次讲解了一下startPreview过程,主要是为了画出一条大致的从上到下的线条,今天我们看一下Camera在Framework的sendCommand和dataCallback,这部分属于衔接过 ...

  9. Laravel Database——Paginate 分页服务源码分析

    paginate 分页 laravel 的分页用起来非常简单,只需要对 query 调用 paginate 函数,把返回的对象扔给前端 blade 文件,在 blade 文件调用函数 render 函 ...

最新文章

  1. 你想了解的Cookie和Session就在这~
  2. 比ajax更好技术,ajax 技术
  3. 易语言基础编程知识〖E语言手册〗
  4. 2*2矩阵训练集比例对BP神经网络分类性能影响
  5. JavaScript --- [学习笔记]观察者模式 理解对象 工厂模式 构造函数模式
  6. jdbc mysql demo_JDBC_demo:java连接mysql过程
  7. java中字符编码详解
  8. 选择一本适合自己的Linux系统书籍
  9. python可视化数据分析交互作用_一文轻松看懂线性回归分析的交互作用!
  10. My_software_list
  11. anywhere随启随用的静态文件服务器
  12. java的property_「propertyutils」java之PropertyUtils - seo实验室
  13. 阿里云服务器ddos攻击防御
  14. 考研操作系统【1.5 操作系统引导与虚拟机】
  15. Python基础-不要对实例属性和类属性使用相同的名字
  16. educoder中Spark GraphX—构建图及相关操作
  17. macw资讯:MacOS如何隐藏、加密文件或文件夹
  18. DS二叉树——Huffman编码与解码(不含代码框架)
  19. 深入分析 Watcher 机制的实现原理(一)客户端注册watcher
  20. Check failed: top_shape[j] == bottom[i]-shape(j) (1 vs. 2) All inputs must have the same shape, exc

热门文章

  1. python模拟登录网站_Python爬虫实战之(四)| 模拟登录京东商城
  2. git commit规范 、CHANGELOG生成 和版本发布的标准自动化
  3. 检测乳腺癌细胞中的有丝分裂(3)
  4. Win10删除微软拼音输入法的方法
  5. 欧拉图与半欧拉图的判断
  6. 公司企业小程序怎么创建?
  7. Name Mangling
  8. Guava学习笔记(转)
  9. MySQL聚簇索引和非聚簇索引的原理及使用
  10. pm2日志文件过大问题解决