目录
前言
之前介绍了U盘的挂载,那当然不能少了U盘的卸载。这里大概的记录一下,方便自己查阅。
Android P
这里很多都是网上的,我就走走流程。
正文
VolumeManager.cpp
handleBlockEvent()
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) { //申请一个lock 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"):""); //判断是否是“disk”类型,磁盘设备,否的话,直接返回不做任何处理 if (devType != "disk") return; //上报的数据中获取主设备号; int major = std::stoi(evt->findParam("MAJOR")); //上报的数据中获取次设备号; int minor = std::stoi(evt->findParam("MINOR")); //makedev()作用是将主次设备号联合得到具体可访问的设备对象索引; dev_t device = makedev(major, minor); //判断事件的动作类型 switch (evt->getAction()) { case NetlinkEvent::Action::kAdd: { //循环判断mDiskSources,这个mDiskSources 在vold的main()函数时就已经配置好的。所以mDiskSources是固定的一些数据。 //在main()函数中调用了process_config()函数对VolumeManager::DiskSource进行赋值。具体是检索配置fstab文件,进行add操作。 for (const auto& source : mDiskSources) { //从mDiskSources表获取的一个成员DiskSource类型的source, //调用该成员的matches函数对 第11行获取的设备路径eventPath,进行匹配字符串比较。 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 USB int flags = source->getFlags(); //判断主设备号是否是mmc的设备; if (major == kMajorBlockMmc //判断是否是模拟器运行的; || (android::vold::IsRunningInEmulator() //判断主设备号必须在 block设备范围内 && major >= (int) kMajorBlockExperimentalMin && major <= (int) kMajorBlockExperimentalMax)) { //将该磁盘Disk的flag标志为kSd flags |= android::vold::Disk::Flags::kSd; } else { //将该磁盘Disk的flag标志为kUsb flags |= android::vold::Disk::Flags::kUsb; } auto disk = new android::vold::Disk(eventPath, device, source->getNickname(), flags); handleDiskAdded(std::shared_ptr<android::vold::Disk>(disk)); break; } } break; } case NetlinkEvent::Action::kChange: { handleDiskChanged(device); break; } case NetlinkEvent::Action::kRemove: { handleDiskRemoved(device); break; } default: { break; } } }
这里是event事件处理中心,主要处理disk类型事件。
以上注册都是摘抄,部分参考文章忘记附上了。
上面分别有三种状态
-
kAdd 挂载
-
kChange
-
kRemove 卸载
我们这里分析U盘的卸载,跟一下流程。
handleDiskRemoved()
void VolumeManager::handleDiskRemoved(dev_t device) { //获取vm管理的mDisks表头 //已经挂载成功的disk auto i = mDisks.begin(); //判断mDisks表是否遍历结束; while (i != mDisks.end()) { //判断从mDisks表取得到的一个Disk的设备 与当前Uevent上报的设备是否一致; if ((*i)->getDevice() == device) { //判断设备比较一样后,将该Disk 从mDisks表里移除; (*i)->destroy(); //删除释放到从mDisks表里移除的Disk; i = mDisks.erase(i); } else { ++i; } } //pending的disk auto j = mPendingDisks.begin(); while (j != mPendingDisks.end()) { if ((*j)->getDevice() == device) { j = mPendingDisks.erase(j); } else { ++j; } } }
上面任务
-
从挂载的磁盘列表中移除当前磁盘,并执行destroy()
-
从Pending的磁盘列表中移除当前磁盘
我们主要关注第一个列表,已经挂载成功的列表中查询并destroy。
Disk.cpp
destroy()
status_t Disk::destroy() { CHECK(mCreated); //销毁所有volume destroyAllVolumes(); mCreated = false; //通知StorageManagerService auto listener = VolumeManager::Instance()->getListener(); if (listener) listener->onDiskDestroyed(getId()); return OK; }
destroyAllVolumes()
void Disk::destroyAllVolumes() { for (const auto& vol : mVolumes) { vol->destroy(); } mVolumes.clear(); }
根据挂载流程中,mVolumes添加的是PublicVolume。
PublicVolume没有重写destroy(),找它父类VolumeBase。
VolumeBase.cpp
status_t VolumeBase::destroy() { CHECK(mCreated); //根据磁盘状态执行不同的需求,如果挂载成功了,就需要unmounted if (mState == State::kMounted) { unmount(); setState(State::kBadRemoval); } else { setState(State::kRemoved); } auto listener = getListener(); if (listener) listener->onVolumeDestroyed(getId()); status_t res = doDestroy(); mCreated = false; LOG(ERROR) << "Water_x VolumeBase destroy 2"; return res; }
这里主要任务
-
判断磁盘状态,如果挂载就需要卸载,然后刷新状态
-
通知StorageManagerService磁盘卸载了
-
调用PublicVolume.doDestroy()
这里已知挂载成功过,也就是此时状态State::kMounted,因此需要unmount()
unmount()
status_t VolumeBase::unmount() { if (mState != State::kMounted) { return -EBUSY; } //设置正在退出状态 setState(State::kEjecting); //不是太理解,上面已经变量过,难道考虑多分区? for (const auto& vol : mVolumes) { if (vol->destroy()) { LOG(WARNING) << getId() << " failed to destroy " << vol->getId() << " stacked above"; } } mVolumes.clear(); //执行doUnmount() status_t res = doUnmount(); setState(State::kUnmounted); return res; }
对于for循环destroy(),不是很理解,这里猜测多分区或插入了Hub的考虑。具体我没有深入,这里不讨论哈。
最后走了doUnmount(),这个虚函数,子类实现了。
PublicVolume.cpp
doUnmount()
status_t PublicVolume::doUnmount() { //kill真正使用路径的进程 KillProcessesUsingPath(getPath()); //强制性卸载 ForceUnmount(mFuseDefault); ForceUnmount(mFuseRead); ForceUnmount(mFuseWrite); ForceUnmount(mRawPath); if (mFusePid > 0) { kill(mFusePid, SIGTERM); TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0)); mFusePid = 0; } rmdir(mFuseDefault.c_str()); rmdir(mFuseRead.c_str()); rmdir(mFuseWrite.c_str()); rmdir(mRawPath.c_str()); mFuseDefault.clear(); mFuseRead.clear(); mFuseWrite.clear(); mRawPath.clear(); return OK; }
里面就懒得继续了跟了,就是卸载磁盘大致流程。
参考文章
历史上的今天
暂无评论...
随机推荐
ARGB 颜色取值与透明度对照表
什么是ARGBARGB 依次代表透明度(alpha)、红色(red)、绿色(green)、蓝色(blue)。Android颜色值格式Android中的颜色值一般格式是:#AARRGGBB。AA就是透明度值RRGGBB是颜色值例子如果UI设计师给的视觉稿标注是:颜色#FFFFFF,透明...
沈从文 : 独处
在我一个自传里,我曾经提到过水给我种种的印象。檐溜、小小的河流、汪洋万顷的大海,莫不对于我有过极大的帮助。我学会用小小脑子去思索一切,全亏得是水。我对于宇宙认识得深一点,也亏得是水。“孤独一点,在你缺少一切的时节,你就会发现,原来还有个你自己。”这是一句真话。我有我自己的生活与理想,可以说是...
Android app换肤简单记录
前言记录一下换肤的思路,方便自己查阅正文Android换肤已经烂大街了,很多大厂应用都做了,比如QQ、网易云、哔哩哔哩等,这些都是需要VVIP才可以体验的。这里推荐GitHub开源的而且很受欢迎的Android-skin-support,很强大。下面我就整理一下我对换肤的简单理解。换...
Android系统切换语言后,Activity中的文本没有改变
前言切换语言后,项目中的APP中的文本没有根据系统的语言改变而改变。这个是个小问题,但还是记录一下,方便自己查阅。正文隐藏内容!付费阅读后才能查看!¥1 ¥3多个隐藏块只需支付一次付费阅读参考文章《[摘]切换多国语言导致Fragment被回收,出现切换错乱》
Android状态栏之TimeView
前言状态栏上使用,TimeView为用于显示当前时间的View,支持24小时制和12小时制自动切换。记录于此,方便自己查阅。正文隐藏内容!付费阅读后才能查看!¥2 ¥3多个隐藏块只需支付一次付费阅读
Vim替换命令
前言简单记录Vim替换命令正文利用:s命令可实现字符串的替换# 命令之间是没有间隔的,下面表示为了看的清晰:范围 s /old /new如果没有指明范围,就表示当前行:s/old/new:s/old/new/g [g 表示当前行匹配的全部替换]:,$s/old/new/g ...