Android 14 vold 分析(2)VolumeManager 和 NetlinkManger
3. VolumeManager::Instance() 和 VolumeManager::start()
system/vold/VolumeManager.cpp
3.1 Instance()没啥好说的 非常简单
112 VolumeManager* VolumeManager::Instance() {113 if (!sInstance) sInstance = new VolumeManager();114 return sInstance;115 }116 117 VolumeManager::VolumeManager() {118 mDebug = false;119 mNextObbId = 0;120 mNextStubId = 0;121 // For security reasons, assume that a secure keyguard is122 // showing until we hear otherwise123 mSecureKeyguardShowing = true;124 }
3.2 VolumeManager::start()
174 int VolumeManager::start() {175 ATRACE_NAME("VolumeManager::start");176 177 // Always start from a clean slate by unmounting everything in178 // directories that we own, in case we crashed.179 unmountAll(); -----> 全部 unmount , 这里的unmount似乎并不是全部所有分区, 全部的话那还了得180 181 Loop::destroyAll();182 183 // Assume that we always have an emulated volume on internal184 // storage; the framework will decide if it should be mounted.185 CHECK(mInternalEmulatedVolumes.empty());186 187 auto vol = std::shared_ptr<android::vold::VolumeBase>(188 new android::vold::EmulatedVolume("/data/media", 0)); ---> 创建 EmulatedVolume189 vol->setMountUserId(0);190 vol->create();191 mInternalEmulatedVolumes.push_back(vol);192 193 // Consider creating a virtual disk194 updateVirtualDisk();195 196 return 0;197 }
4. NetlinkManger::Instance() 和 NetlinkManger::start()
system/vold/NetlinkManager.cpp
4.1 NetlinkManger::Instance() 很简单 不需要赘述
36 NetlinkManager* NetlinkManager::Instance() {37 if (!sInstance) sInstance = new NetlinkManager();38 return sInstance;39 }40 41 NetlinkManager::NetlinkManager() {42 mBroadcaster = NULL;43 }
4.2 NetlinkManger::start()
47 int NetlinkManager::start() {48 struct sockaddr_nl nladdr;49 int sz = 64 * 1024;50 int on = 1;51 52 memset(&nladdr, 0, sizeof(nladdr));53 nladdr.nl_family = AF_NETLINK;54 nladdr.nl_pid = getpid();55 nladdr.nl_groups = 0xffffffff;56 57 if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT)) < 0) { ---> 创建socket client58 PLOG(ERROR) << "Unable to create uevent socket";59 return -1;60 }61 62 // When running in a net/user namespace, SO_RCVBUFFORCE will fail because63 // it will check for the CAP_NET_ADMIN capability in the root namespace.64 // Try using SO_RCVBUF if that fails.65 if ((setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) &&66 (setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0)) {67 PLOG(ERROR) << "Unable to set uevent socket SO_RCVBUF/SO_RCVBUFFORCE option";68 goto out;69 }70 71 if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {72 PLOG(ERROR) << "Unable to set uevent socket SO_PASSCRED option";73 goto out;74 }75 76 if (bind(mSock, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0) { --> socket bind77 PLOG(ERROR) << "Unable to bind uevent socket";78 goto out;79 }80 81 mHandler = new NetlinkHandler(mSock); --> 创建 new NetlinkHandler82 if (mHandler->start()) { --> 创建 new NetlinkHandler.start() 见4.383 PLOG(ERROR) << "Unable to start NetlinkHandler";84 goto out;85 }86 87 return 0;88 89 out:90 close(mSock);91 return -1;92 }
4.3 new NetlinkHandler and start()
这有个继承关系NetlinkHandler : NetlinkListener : SocketListener
2 int NetlinkHandler::start() {33 return this->startListener(); ------> 实际就是SocketListener poll监听,是否有POLLIN 产生, onDataAvailable -> onEvent34 }35 36 void NetlinkHandler::onEvent(NetlinkEvent* evt) { ---> 收到了uevent37 VolumeManager* vm = VolumeManager::Instance();38 const char* subsys = evt->getSubsystem();39 40 if (!subsys) {41 LOG(WARNING) << "No subsystem found in netlink event";42 return;43 }44 45 if (std::string(subsys) == "block") { ------> 只有uevent的subsys是block才会处理的46 vm->handleBlockEvent(evt); ------> VolumeManager处理 block device uevent 见 4.447 }48 }
4.4 VolumeManager::handleBlockEvent()
199 void VolumeManager::handleBlockEvent(NetlinkEvent* evt) {200 std::lock_guard<std::mutex> lock(mLock);201 202 if (mDebug) {203 LOG(DEBUG) << "----------------";204 LOG(DEBUG) << "handleBlockEvent with action " << (int)evt->getAction(); ---> 这里是vold.debug控制的,打印具体的action205 evt->dump();206 }207 208 std::string eventPath(evt->findParam("DEVPATH") ? evt->findParam("DEVPATH") : "");209 std::string devType(evt->findParam("DEVTYPE") ? evt->findParam("DEVTYPE") : "");210 211 if (devType != "disk") return; ---> devType不是disk还不处理, 真是牛逼哄哄212 213 int major = std::stoi(evt->findParam("MAJOR"));214 int minor = std::stoi(evt->findParam("MINOR"));215 dev_t device = makedev(major, minor); ---> 创建block device组合216 217 switch (evt->getAction()) {218 case NetlinkEvent::Action::kAdd: { ---> uevent action为add 具体见4.5219 for (const auto& source : mDiskSources) { ---> 之前添加的两个disksource,还记得吗,只支持sd卡和U盘220 if (source->matches(eventPath)) {221 // For now, assume that MMC and virtio-blk (the latter is222 // specific to virtual platforms; see Utils.cpp for details)223 // devices are SD, and that everything else is USB224 int flags = source->getFlags();225 if (major == kMajorBlockMmc || IsVirtioBlkDevice(major)) {226 flags |= android::vold::Disk::Flags::kSd; ---> SD卡227 } else {228 flags |= android::vold::Disk::Flags::kUsb; ---> usb storage, 通过otg插入的229 }230 231 auto disk =232 new android::vold::Disk(eventPath, device, source->getNickname(), flags); ---> 创建一个disk设备节点mknod233 handleDiskAdded(std::shared_ptr<android::vold::Disk>(disk)); --> 真正的处理234 break;235 }236 }237 break;238 }239 case NetlinkEvent::Action::kChange: { --> uevent action为add 具体见4.6240 LOG(VERBOSE) << "Disk at " << major << ":" << minor << " changed";241 handleDiskChanged(device);242 break;243 }244 case NetlinkEvent::Action::kRemove: { --> uevent action为add 具体见4.7245 handleDiskRemoved(device);246 break;247 }248 default: {249 LOG(WARNING) << "Unexpected block event action " << (int)evt->getAction();250 break;251 }252 }253 }
4.5 new android::vold::Disk()和handleDiskAdded()
system/vold/model/Disk.cpp
4.5.1 new android::vold::Disk()
Disk::Disk(const std::string& eventPath, dev_t device, const std::string& nickname, int flags)95 : mDevice(device),96 mSize(-1),97 mNickname(nickname),98 mFlags(flags),99 mCreated(false),100 mJustPartitioned(false) {101 mId = StringPrintf("disk:%u,%u", major(device), minor(device));102 mEventPath = eventPath;103 mSysPath = StringPrintf("/sys/%s", eventPath.c_str());104 mDevPath = StringPrintf("/dev/block/vold/%s", mId.c_str());105 CreateDeviceNode(mDevPath, mDevice); ---------> 创建block device 的设备节点mknod106 }
4.5.2 handleDiskAdded()
255 void VolumeManager::handleDiskAdded(const std::shared_ptr<android::vold::Disk>& disk) {256 // For security reasons, if secure keyguard is showing, wait257 // until the user unlocks the device to actually touch it258 // Additionally, wait until user 0 is actually started, since we need259 // the user to be up before we can mount a FUSE daemon to handle the disk.260 bool userZeroStarted = mStartedUsers.find(0) != mStartedUsers.end();261 if (mSecureKeyguardShowing) {262 LOG(INFO) << "Found disk at " << disk->getEventPath()263 << " but delaying scan due to secure keyguard";264 mPendingDisks.push_back(disk);265 } else if (!userZeroStarted) {266 LOG(INFO) << "Found disk at " << disk->getEventPath()267 << " but delaying scan due to user zero not having started";268 mPendingDisks.push_back(disk);269 } else {270 disk->create(); ---------> disk->create()271 mDisks.push_back(disk);272 }273 }146 status_t Disk::create() {147 CHECK(!mCreated);148 mCreated = true;149 150 auto listener = VolumeManager::Instance()->getListener(); ---------> StorageManaerService通信151 if (listener) listener->onDiskCreated(getId(), mFlags); ------> StorageManaerService->onDiskCreated()152 153 if (isStub()) {154 createStubVolume();155 return OK;156 }157 readMetadata(); --------> listener->onDiskMetadataChanged(getId(), mSize, mLabel, mSysPath);158 readPartitions(); --------> Disk::createPublicVolume() listener->onVolumeCreated()and listener->onDiskScanned()159 return OK;160 }
思考, vold比mount service启动的早,那开机时vold获取到的listener为空,也就是说虽然disk创建了但是不会mount,那什么时候才会mount呢? 我们下一篇文章解答
相关文章:
Android 14 vold 分析(2)VolumeManager 和 NetlinkManger
3. VolumeManager::Instance() 和 VolumeManager::start() system/vold/VolumeManager.cpp 3.1 Instance()没啥好说的 非常简单 112 VolumeManager* VolumeManager::Instance() {113 if (!sInstance) sInstance new VolumeManager();114 return sInst…...

《黑马点评》Redis高并发项目实战笔记(上)P1~P45
P1 Redis企业实战课程介绍 P2 短信登录 导入黑马点评项目 首先在数据库连接下新建一个数据库hmdp,然后右键hmdp下的表,选择运行SQL文件,然后指定运行文件hmdp.sql即可(建议MySQL的版本在5.7及以上): 下面这…...

pytorch车牌识别
目录 使用pytorch库中CNN模型进行图像识别收集数据集定义CNN模型卷积层池化层全连接层 CNN模型代码使用模型 使用pytorch库中CNN模型进行图像识别 收集数据集 可以去找开源的数据集或者自己手做一个 最终整合成 类别分类的图片文件 定义CNN模型 卷积层 功能:提…...

【C++入门】内联函数、auto与基于范围的for循环
💞💞 前言 hello hello~ ,这里是大耳朵土土垚~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 💥个人主页&#x…...
服务器停用,备份服务文件。
文章目录 引言I 文件备份1.1 数据库文件/证书1.2 redis1.3 nacosII JAVA流水线备份2.1 java构建2.2 镜像构建2.3 docker 部署2.4 子模块构建2.5 Dockerfile_prodIII VUE项目流水线备份3.1 Node.js 构建3.2 Dockerfile_prod...

基于Python的深度学习的中文情感分析系统(V2.0),附源码
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...

使用Postman发送跨域请求实验
使用Postman发送跨域请求 1 跨域是什么?2 何为同源呢?3 跨域请求是如何被检测到的?4 Postman跨域请求测试4.1 后端准备4.2 测试用例4.2.1 后端未配置跨域请求(1) 前端不跨域(2)前端跨域 4.2.2 后端配置跨域信息(1&…...

4、jvm-垃圾收集算法与垃圾收集器
垃圾收集算法 分代收集理论 当前虚拟机的垃圾收集都采用分代收集算法,这种算法没有什么新的思想,只是根据对象存活周期的不同将内存分为几块。一般将java堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。 比如…...
[Excel]如何限制儲存格輸入格式? 以“字首為英文字母大寫,其餘為數字,共15碼“為範例
[Excel]如何限制儲存格輸入格式 需求: 當一個excel表格需要由多位使用者來輸入資料時,難免會出現資料輸入錯誤問題,尤其是料號,品號或是訂單號的長類型編碼。若是問題屬於輸入錯誤"資料"但格式未錯誤,則可能需要讓exce…...

错题记录-华为海思
华为 海思数字芯片 参考 :FPGA开发/数字IC笔试系列(5) 华为海思IC笔试解析 FPGA开发/数字IC笔试系列(6) 华为海思IC笔试解析 SystemVerilog Function与Task的区别 $readmemh与$readmemb这两个系统任务是用来从指定文件中读取数据到寄存器数组或者RAM、ROM中。除了…...

rspack 使用构建vue3脚手架
基于 Rust 的高性能 Web 构建工具。rspack 主要适配 webpack 生态,对于绝大多数 webpack 工具库都是支持的。 启动速度快;增量热更新快。兼容 webpack 生态;内置了 ts、jsx、css、css modules 等开箱即用。生产优化,tree shaking…...

maven之pom中的build标签
1、build标签分类 1.1、全局配置(project build) 针对整个项目的所有情况都有效。 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation"htt…...

Cesium.js--》探秘Cesium背后的3D模型魔力—加载纽约模型
今天简单实现一个Cesium.js的小Demo,加强自己对Cesium知识的掌握与学习,先简单对这个开源库进行一个简单的介绍吧! Cesium 是一个开源的地理空间可视化引擎,用于创建基于 Web 的三维地球应用程序。它允许开发人员在网页上呈现高度…...

.NET i18n 多语言支持与国际化
环境 WIN10 VS2022 .NET8 1.👋创建项目 2.👀创建Resources Controllers HomeController.en.resx HomeController.fr.resx HomeController.zh.resx 3.🌱Program.cs添加国际化支持 // 添加国际化支持 builder.Services.AddLocalization(…...

基于Pytorch实现图像分类——基于jupyter
分类任务 网络基本构建与训练方法,常用函数解torch.nn.functional模块nn.Module模块 MNIST数据集下载 from pathlib import Path import requestsDATA_PATH Path("data") PATH DATA_PATH / "mnist"PATH.mkdir(parentsTrue, exist_okTrue)U…...

如何将CSDN的文章以PDF文件形式保存到本地
1.F12 打开开发者工具窗口 2.console下输入命令 (function(){$("#side").remove();$("#comment_title, #comment_list, #comment_bar, #comment_form, .announce, #ad_cen, #ad_bot").remove();$(".nav_top_2011, #header, #navigator").remove…...
面试经典150题——删除有序数组中的重复项
面试经典150题 day3 题目来源我的题解方法一 双指针 题目来源 力扣每日一题;题序:26 我的题解 方法一 双指针 使用两个指针分别指向相同元素的左右边界,再利用一个count记录最终需要的数组长度。 时间复杂度:O(n) 空间复杂度&a…...
Unity3D知识点精华浓缩
一、细节 1、类与组件的关系 2、Time.deltaTime的含义 3、怎么表示一帧的移动距离 4、Update和LateUpdate的区别和适用场景 5、找游戏对象的方式(别的对象 / 当前对象的子对象) 6、组件1调用组件2中方法的方式 7、在面板中获取外部数据的方法 8、序列化属…...
HTML的文档说明
1.告诉浏览器当前网页的版本 2.写法: !以前的写法:要依据网页的HTML的版本去确定,紫萼发油很多很多。 具体的写法可以参考:W3C官网的文档说明 !新写法:W3C都推荐用h5的写法 <DOCTYPE ht…...
ubuntu 更新或更改GCC/G++
最近遇到一些问题,需要用到gcc-9/g-9,但是我自带的ubuntu18.04是gcc-7.5/g-7.5,所以升级一下,奈何文章太多而且很多无效,所以在此记录一下: 参考:https://stackoverflow.com/questions/19836858…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...

dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》
🧠 LangChain 中 TextSplitter 的使用详解:从基础到进阶(附代码) 一、前言 在处理大规模文本数据时,特别是在构建知识库或进行大模型训练与推理时,文本切分(Text Splitting) 是一个…...

yaml读取写入常见错误 (‘cannot represent an object‘, 117)
错误一:yaml.representer.RepresenterError: (‘cannot represent an object’, 117) 出现这个问题一直没找到原因,后面把yaml.safe_dump直接替换成yaml.dump,确实能保存,但出现乱码: 放弃yaml.dump,又切…...