Android5.0 外部磁盘管理(代码摘自google)
  HvTJUzsxOBtS 2023年11月25日 25 0


一、 整体架构分析
1.1 应用程序接口API
1.1.1 文件位置
frameworks/base/core/java/android/os/storage/StorageManager.java
1.1.2整体框架
Vold - Volume Daemon存储类的守护进程,作为Android的一个本地服务,负责处理诸如SD、USB等存储类设备的插拔等事件。

Vold服务由volumeManager统一管控,它将具体任务分别分派给netlinkManager, commandListener, directVolume, Volume去完成。

Android5.0 外部磁盘管理(代码摘自google)_android


Vold服务向下通过 vold 启动在init.rc中

(1)Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最常用的接口。Netlink套接字可以使用标准的套接字APIs来创建。

1.1.3 Android 磁盘管理总共涉及到四大部分源码
(1)Linux Kernel:Android建立在Linux 内核的基础上,最底层的部分由Linux Kernel来负责,用于检测热插拔事件。
(2)Vold :Android没有使用Linux 平台下的Udev来处理,用了类似Udev的Vold,充当了Kernel与FrameWork之间桥梁。
(3)FrameWork:Android的核心框架,负责操作Vold,给Vold下发操作命令。
(4)UI:Android的系统应用,与FrameWork进行交互,用于挂载/卸载SD卡。
1.1.4 Android 挂载SD卡,流程如下
(1)用户在”设置”页面的“SD卡和手机内存”中点击挂载;
(2)UI从FrameWork获取操作磁盘的函数(向FrameWork注册,才能使用的函数),然后调用挂载的处理函数。
(3)该处理函数通过广播机制发送挂载命令”volume mount sdcard”,vold接受命令并挂载SD卡,并用广播通知FrameWork
(4)FrameWork收的挂载SD卡的 回复,通知UI的处理结果。
(5)界面显示挂载成功/挂载失败。
1.1.5主要涉及的类
三大管理类:VolumeManager,CommandListener,NetlinkManager
其他处理类:Volume,DirectVolume,NetlinkHandler,Fat,ResponseCode
其他相关的类:NetlinkListener,SocketListener

(1)VolumeManager管理Volume类
(2)DirectVolume类继承Volume类,保存磁盘信息与操作函数
(3)NetlinkManager类负责与内核uevent事件通信,期间使用到了NetlinkListener和SocketListener类的函数。
(4)Fat是格式化SD卡的函数。
(5)ResponseCode保存着vold向FrameWork反馈的值。
二、vold 监听处理内核消息

2.1 vold 启动在init.rc中
2.1.1 文件位置

vi ./system/core/rootdir/init.rc

2.1.2 创建socket 用于FrameWork与Vold 通信

Android5.0 外部磁盘管理(代码摘自google)_初始化_02


这里创建一个socket,用于Vold和FrameWork层通信

2.2 跳转到 main.cpp,初始化vold
2.2.1文件位置

vim ./system/vold/main.cpp

2.2.2 创建VolumeManager和NetlinkManager,CommandListener实例,读取配置文件

CommandListener主要负责与FrameWork层的通信,处理从FrameWork层收到的各种命令。

VolumeManager主要负责Voluem的一些管理。

NetlinkManager主要负责管理与内核之间的通信 。

创建VolumeManager和NetlinkManager,CommandListener实例(1)Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最常用的接口。Netlink套接字可以使用标准的套接字APIs来创建。

Android5.0 外部磁盘管理(代码摘自google)_初始化_03


Android5.0 外部磁盘管理(代码摘自google)_初始化_04


Android5.0 外部磁盘管理(代码摘自google)_Android_05


Android5.0 外部磁盘管理(代码摘自google)_初始化_06


Android5.0 外部磁盘管理(代码摘自google)_磁盘管理_07


2.3对 vold.fstab 配置文件的分析 ? (找不到)

(1) 可以根据这个目录找到如下节点:

sh-4.1# ls /dev/block/vold/

179:0 179:1 8:0 8:1 8:2 8:3 8:4

节点的小介绍:

0代表当前的整个设备,1代码当前设备的分区名称代号。

所以你会发现,sdcard只有一个分区它却生成了两个如:179:0 179:1 而usbdisk 有四个分区,它会生成五个挂载点: 8:0 8:1 8:2 8:3 8:4 就是这个原因

(2)vold 里面会通过指定文件来读取预先配置好的sdcard或者多分区配置文件,该文件位于
/system/core/rootdir/etc/vold.fstab
如以下的配置文件为:
dev_mount sdcard /mnt/sdcard auto /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1

dev_mount 代表挂载格式
sdcard 代表挂载的标签
/mnt/sdcard 代表挂载点
auto 为自定义选项可以为任何,但必须在main 里面自己判断比如这里的意思为自动挂载
后面两个目录为设备路径,第一个如果被占用会选择第二个

2.4跳到NetlinkManager.cpp,,管理捕获内核uevent
2.4.1文件位置
vi ./system/vold/NetlinkManager.cpp

2.4.2 创建Netlink套接字用户与内核通信监听内核事件

(1)Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最常用的接口。Netlink套接字可以使用标准的套接字APIs来创建。

在Main.cpp文件中的main函数里面,有一个准备工作用来开启监听内核uevent事件的线程,源码如下:

Android5.0 外部磁盘管理(代码摘自google)_磁盘管理_08


nm是NetlinkManager类实例化的一个对象,以下是start()函数的源码:

Android5.0 外部磁盘管理(代码摘自google)_初始化_09


我们跟进mHandler->start()最终调用 SocketListener::startListener() 2.5跳到NetlinkHandler.cpp,追踪NetlinkHandler::start()

2.5.1文件位置

vi system/vold/NetlinkHandler.cpp

2.5.2 NetlinkHandler::start()函数定义

Android5.0 外部磁盘管理(代码摘自google)_套接字_10


2.6 跳转到SocketListener.cpp,追踪SocketListener::startListener()函数

2.6.1 文件位置
vi system/core/libsysutils/src/SocketListener.cpp

2.6.2 SocketListener::startListener()函数

Android5.0 外部磁盘管理(代码摘自google)_Android_11


Android5.0 外部磁盘管理(代码摘自google)_磁盘管理_12


Android5.0 外部磁盘管理(代码摘自google)_套接字_13


Android5.0 外部磁盘管理(代码摘自google)_Android_14


Android5.0 外部磁盘管理(代码摘自google)_初始化_15


2.7跳到 NetlinkListener.cpp,寻找onDataAvailable()函数,执行内核事件

2.7.1文件位置

vi system/core/libsysutils/src/NetlinkListener.cpp

2.7.2 NetlinkListener::onDataAvailable()函数执行内核事件

Android5.0 外部磁盘管理(代码摘自google)_android_16


上面我们了解到了NetlinkHandler类中的onEvent函数,该函数由NetlinkListener::onDataAvailable函数调用,当SocketListener类监听到内核的uevent事件,调用该函数,之后的事情交给onEvent来负责2.8 跳到NetlinkHandler.cpp,寻找 NetlinkHandler::onEvent()函数

2.8.1文件位置

vi system/vold/NetlinkHandler.cpp

2.8.2 NetlinkHandler::onEvent()函数处理监听事件

Android5.0 外部磁盘管理(代码摘自google)_磁盘管理_17


2.9跳到VolumeManager.cpp,寻找VolumeManager::handleBlockEvent()函数

2.9.1 文件位置

vi system/vold/VolumeManager.cpp2.9.2 VolumeManager::handleBlockEvent()函数获取磁盘信息 

Android5.0 外部磁盘管理(代码摘自google)_初始化_18


2.10跳到Volume.cpp,Volume::handleBlockEven()函数

2.10.1 文件位置vi system/vold/Volume.cpp

2.10.2 Volume::handleBlockEven()函数

Android5.0 外部磁盘管理(代码摘自google)_初始化_19


2.11跳到 DirectVolum

Android5.0 外部磁盘管理(代码摘自google)_套接字_20

e.cpp,追踪DirectVolume::handleBlockEvent()函数

2.11.1文件位置

vi system/vold/DirectVolume.cpp

2.11.2 DirectVolume::handleBlockEvent()函数 磁盘处理函数

Android5.0 外部磁盘管理(代码摘自google)_android_21


Android5.0 外部磁盘管理(代码摘自google)_android_22


Android5.0 外部磁盘管理(代码摘自google)_android_23


Android5.0 外部磁盘管理(代码摘自google)_android_24


Android5.0 外部磁盘管理(代码摘自google)_android_25


Android5.0 外部磁盘管理(代码摘自google)_初始化_26


Android5.0 外部磁盘管理(代码摘自google)_套接字_27


Android5.0 外部磁盘管理(代码摘自google)_磁盘管理_28


前面介绍了磁盘事件的处理,监听了磁盘的插拔,这些工作就是在main函数中的nm->start()函数负责的,下面分析其他处理函数了,但这些事件的处理起着至关重要的作用,如果没有做这些工作,framework也就根本不理会也不知道底层发生了什么事情。三、FrameWork与Vold通信链路

vold处理完磁盘事件,就要开始接受framework的操作命令,在main函数里面,开启了一个线程来监听framework的信息,当收到操作命令,vold进行解析,分析出命令,然后调用相应的磁盘操作函数,待操作完成后,再将操作结果的状态值反馈给framework,中间均使用了广播机制,使用了UDP协议。

3.1跳转到main.cpp,开启FrameWork信号监听函数

3.1.1文件位置

vim ./system/vold/main.cpp

3.1.2 startListen()函数监听FW命令

在main()函数里面

Android5.0 外部磁盘管理(代码摘自google)_磁盘管理_29


cl是CommandListener类实例化的一个对象,该对象专门负责与framework的通信,首先说明与CommandListener类相关的一些继承关系。

CommandListener –> FrameworkListener –> SocketListener(父类)

进入startListener函数,创建了以下线程:

3.2 跳转到SocketListener.cpp,创建监听线程

3.2.1 文件位置

system/core/libsysutils/src/SocketListener.cpp

3.2.2 pthread_creat()-》threadstart()->runlistener()函数

Android5.0 外部磁盘管理(代码摘自google)_android_30

Android5.0 外部磁盘管理(代码摘自google)_初始化_31


Android5.0 外部磁盘管理(代码摘自google)_初始化_32


Android5.0 外部磁盘管理(代码摘自google)_套接字_33


Android5.0 外部磁盘管理(代码摘自google)_初始化_34


3.3跳到 FrameworkListener.cpp,执行onDataAvailable()函数3.3.1文件位置

vi system/core/libsysutils/src/FrameworkListener.cpp

3.3.2 onDataAvailable()函数,处理FrameWork命令

Android5.0 外部磁盘管理(代码摘自google)_Android_35

3.3.2追踪dispatchcommand()函数,选择不同的分支函数

vi system/core/libsysutils/src/FrameworkListener.cpp

Android5.0 外部磁盘管理(代码摘自google)_Android_36


Android5.0 外部磁盘管理(代码摘自google)_套接字_37


Android5.0 外部磁盘管理(代码摘自google)_套接字_38


这个循环为什么可以选择不同的分支新实现的函数呢?

仔细看下代码会发现,在FrameworkListener中有一个注册函数,将新的派生类的名字注册到mCommands容器中,每个类的mCommand参数各代表一个派生类的名字。3.3.3注册新生类函数

Android5.0 外部磁盘管理(代码摘自google)_Android_39


在CommandListener类的构造函数中,分别对6个分支的派生类进行了注册,每次注册都实例化了一个新的对象存放到mCommands容器中。3.4 跳转到system/vold/CommandListener.cpp中,注册6个commandlistener类

3.4.1文件位置

vi system/vold/CommandListener.cpp

3.4.2 6个commandlistener类注册时实例化对象,保存在mCommands容器

Android5.0 外部磁盘管理(代码摘自google)_初始化_40

那这6个派生类的名称保存在FrameworkCommand类的一个私有变量mCommand中,该类的构造函数就是给mCommand赋值

这里来看mCommand的赋值,我们知道以下关系:

DumpCmd –> VoldCommand –> FrameworkCommand

VolumeCmd –> VoldCommand –> FrameworkCommand

ShareCmd –> VoldCommand –> FrameworkCommand

AsecCmd –> VoldCommand –> FrameworkCommand

StorageCmd –> VoldCommand –> FrameworkCommand

XwarpCmd –> VoldCommand –> FrameworkCommand

所以在CommandListener类中的6个派生类中的构造函数中,必须初始化const char *cmd这个参数,以下是初始化代码:

例如:

Android5.0 外部磁盘管理(代码摘自google)_套接字_41


6个构造函数均初始化不同的cmd参数,分别为dump,volume,share,storage,asec,xwarp。

在VoldCommand类的构造函数中,将cmd的值初始化FrameworkCommand类的构造函数

3.5跳转到 VoldCommand.cpp,实现FrameworkCommand(cmd)

3.5.1文件位置

vi system/vold/VoldCommand.cpp

3.5.2 FrameWorkCommand()函数实现

Android5.0 外部磁盘管理(代码摘自google)_磁盘管理_42


3.6跳到 FrameworkCommand.cpp,对mcommand赋值

3.6.1文件位置

vi system/core/libsysutils/src/FrameworkCommand.cpp

3.6.2FrameworkCommand::FrameworkCommand()函数,对mcommand赋值

Android5.0 外部磁盘管理(代码摘自google)_Android_43


这样刚才的FrameworkListener::dispatchCommand函数里的c->getcommand()就可以比较命令了。

就是将framework发下来的命令的第一个参数与mCommands容器中的6个对象的mCommand参数进行了比较,从而选择正确的处理分支函数。

现在流程就走到了runCommand函数,该函数就声明在最上面那个CommandListener类里面

四、Vold 处理FrameWork命令消息

说了这么多,该到执行命令的函数了,要不黄花菜都凉了。上面讲了vold如何开启接收framework下发命令的线程,最终到了runCommand函数的实现,总共有6个版本,由于重复性大,只讲VolumeCmd类的runCommand函数的实现。
VolumeCmd可以说是最重要的,该类的实现处理了list,debug,mount,unmount,format,unshare,shared等等操作,详细说明:
list: 在启动vold之后,接收的第一条命令就是list,这里是获取系统的所有磁盘对象,一般只有sd卡。
debug: 设置USB的调试模式
mount: 挂载磁盘
unmount: 卸载磁盘
format: 格式化磁盘
unshare: 关闭USB的大容量存储模式,相当于断开手机与电脑的连接
shared: 开启USB的大容量存储模式,相当于手机与电脑连接,并挂载在电脑

4.1跳到CommandListener.cpp,实现runCommand()函数

4.1.1文件位置

vi system/vold/CommandListener.cpp

4.1.2 runCommand()函数,执行FW命令

Android5.0 外部磁盘管理(代码摘自google)_android_44


Android5.0 外部磁盘管理(代码摘自google)_Android_45


Android5.0 外部磁盘管理(代码摘自google)_android_46


4.2 跳转到VolumeManager.cpp,实现命令具体函数

4.2.1文件位置

vi system/vold/VolumeManager.cpp4.2.2 listVolumes()函数,获取磁盘信息

Android5.0 外部磁盘管理(代码摘自google)_Android_47


4.2.3 setDebug()设置调试模式->(vi system/vold/Volume.cpp)

Android5.0 外部磁盘管理(代码摘自google)_android_48


vi system/vold/Volume.cpp

Android5.0 外部磁盘管理(代码摘自google)_磁盘管理_49


4.2.4 mountVolume() 挂载函数

Android5.0 外部磁盘管理(代码摘自google)_初始化_50


Android5.0 外部磁盘管理(代码摘自google)_android_51


4.3 跳转到Volume.cpp,寻找mountvol函数

4.3.1文件位置

vi system/vold/Volume.cpp

4.3.2 mountvol()函数执行挂载命令

Android5.0 外部磁盘管理(代码摘自google)_Android_52


Android5.0 外部磁盘管理(代码摘自google)_初始化_53


Android5.0 外部磁盘管理(代码摘自google)_套接字_54


Android5.0 外部磁盘管理(代码摘自google)_初始化_55


Android5.0 外部磁盘管理(代码摘自google)_初始化_56


getDeviceNodes函数获取挂载设备的设备号与分区数量,是Volume类的一个纯虚函数,在子类DirectVolume中实现,源码:

4.4 跳到DirectVolume.cpp,实现getDeviceNodes()函数
4.4.1文件位置

vi system/vold/DirectVolume.cpp

4.4.2 getDeviceNodes()函数,获取设备号,分区数量

Android5.0 外部磁盘管理(代码摘自google)_android_57


4.5 跳到 Fat.cpp ,寻找Fat:doMount()函数,实现挂载

4.5.1文件位置

vi system/vold/Fat.cpp

4.5.2 Fat:doMount()函数,实现对磁盘的挂载

Android5.0 外部磁盘管理(代码摘自google)_套接字_58


Android5.0 外部磁盘管理(代码摘自google)_套接字_59


4.6 跳到 VolumeManager.cpp,寻找unmountVolume()强制卸载函数

4.6.1文件位置

vi system/vold/VolumeManager.cpp4.6.2 unmountVolume()强制卸载函数

Android5.0 外部磁盘管理(代码摘自google)_Android_60


4.7 跳到 volume.cpp,寻找volume::unmountVol()函数实现卸载

4.7.1文件位置vi system/vold/Volume.cpp

4.7.2 volume::unmountVol()函数实现卸载

Android5.0 外部磁盘管理(代码摘自google)_套接字_61


4.8 跳到DirectVolume.cpp ,vold捕获移除事件,调用handleDiskRemoved; handlePartitionRemoved

卸载函数:

4.8.1文件位置
vi system/vold/DirectVolume.cpp

4.8.2 handleDiskRemoved; handlePa。

rtitionRemoved()卸载函数

Android5.0 外部磁盘管理(代码摘自google)_Android_62


Android5.0 外部磁盘管理(代码摘自google)_磁盘管理_63


Android5.0 外部磁盘管理(代码摘自google)_套接字_64


4.9 跳到Volume.cpp,寻找formatVol()函数实现格式化

本文开始讨论sd卡的格式化功能,平时使用windows操作系统,也经常格式化磁盘。涉及到的

操作有这几步:

1.将分区信息写到硬盘的第一个设备节点的MBR结构中的分区表;

2.格式化分区到指定的文件系统类型

MBR中存放分区表的位置在446-509,占用了64字节,MBR结构只支持4个主分区,所以
有4个16字节的区域,先简要说明一下MBR的分区表的结构

从这个表格可以看出,相对于446-509的分区表区域,每个主分区的第5个字节存放的是文件

系统标志位,用来识别什么分区,用fdisk工具查看一下,有如下文件系统对应的十六进制标志:

若需要读取这些文件系统标志,只需读取MBR的450个位置,占用一个字节大小。

要分析Android格式化sd卡的功能,在格式化部分,涉及到了系统的一些函数,与vold无关,简单的说明一下即可。
Android系统在格式化sd卡的时候,首先会判断sd卡是否存在分区,如果sd卡不存在分区,
那么需要重新初始化MBR区域,所以上面简要的介绍了MBR结构中分区表的区域。

4.9.1文件位置

vi system/vold/Volume.cpp

4.9.2 formatVol()函数实现SD卡格式化

Android5.0 外部磁盘管理(代码摘自google)_Android_65


Android5.0 外部磁盘管理(代码摘自google)_磁盘管理_66


Android5.0 外部磁盘管理(代码摘自google)_Android_67


跟进 initializeMbr()函数,得到两个结构体的定义:part_info;disk_info文件位置:

(system/core/include/diskconfig/diskconfig.h)

Android5.0 外部磁盘管理(代码摘自google)_android_68


初始化完成后,将该结构体变量dinfo通过apply_disk_config函数进行设置:

4.10 跳到diskconfig.c ,实现apply_disk_config函数设置

4.10.1文件位置

vi system/core/libdiskconfig/diskconfig.c

4.10.2 apply_disk_config()函数设置变量 dinfo

Android5.0 外部磁盘管理(代码摘自google)_android_69


该函数先打开sd卡的设备节点,然后将MBR的初始化信息写到第一个block(512B)中,

这里涉及到非常多函数,不在vold的讨论范围。

写完MBR后,就要对分区进行格式化,要格式化成FAT32格式,Fat::format函数直接调用

系统命令newfs_msdos来格式化新分区,检测磁盘是,Fat::check函数直接调用系统命令

fsck_msdos来检测分区。

最后格式化完成通知FrameWork,SD处于空闲状态

4.11 跳到Fat.cpp,调用Fat::format进行格式化磁盘

4.11.1文件位置

system/vold/Fat.cpp

4.11.2 Fat::format()函数实现SD卡格式化

Android5.0 外部磁盘管理(代码摘自google)_Android_70


Android5.0 外部磁盘管理(代码摘自google)_android_71


4.11.3 Fat::check()函数检测磁盘分区

Android5.0 外部磁盘管理(代码摘自google)_套接字_72


Android5.0 外部磁盘管理(代码摘自google)_套接字_73


4.12 跳到CommandListener.cpp OTG链接分析

OTG是on-the-go的简称,是2001年由USB Implementers Forum公布,主要应用于各种不同的设备或移动设备间的联接,进行数据交换。特别是PDA、移动电话、消费类设备。改变如数码照相机、摄像机、打印机等 设备间多种不同制式连接器,多达7种制式的存储卡间数据交换的不便。
这里写得很清楚,OTG主要是实现可移动设备点对点的数据共享,不需要再依赖于PC机第三方的识别或者操作。平时经常从电脑下载MP3格式的音乐到 phone or Pad,都是经过USB线来连接电脑,电脑可以识别到设备里面的存储设备,或者手机与手机的连接,这就是OTG功能。
Linux内核早就提供了OTG的驱动。在/drivers/usb/gadget/目录下,Linux将USB与OTG两个功能模块独立开来,主要的驱动是file_storage.c,该驱动主要负责终端设备的存储设备节点的操作,比如,从电脑,从终端的磁盘上面创建文件,都会通过这个驱动来完成存储任务。另外一个驱动主要是负责USB通信,是结尾“_udc.c”的驱动源码,该目录下有好几个以“_udc.c”结尾的文件,这是针对不同的型号处理器而增加的,不同的厂家提供不同的驱动。
这里简单介绍一下,Android在Vold中处理OTG,就是将要共享的磁盘设备写到一个标志文件里面,在广播一下大容量存储链接状态。

4.12.1 文件位置
vi system/vold/CommandListener.cpp

4.12.2 OTG 链接电脑

Android5.0 外部磁盘管理(代码摘自google)_套接字_74


4.13 跳到 VolumeManager.cpp ,寻找shareVolume()函数

4.13.1文件位置

vi system/vold/VolumeManager.cpp

4.13.2 shareVolume()函数 ,链接OTG

Android5.0 外部磁盘管理(代码摘自google)_初始化_75


Android5.0 外部磁盘管理(代码摘自google)_android_76


4.13.3 unshareVolume(),断开连接函数

Android5.0 外部磁盘管理(代码摘自google)_磁盘管理_77


Android5.0 外部磁盘管理(代码摘自google)_磁盘管理_78


4.14跳到 DirectVolume.cpp, 寻找handleVolumeshared();handVolumeUnshared函数

4.14.1文件位置

vi system/vold/DirectVolume.cpp4.14.2 handleVolumeshared();handVolumeUnshared函数,OTG链接,断开广播

Android5.0 外部磁盘管理(代码摘自google)_套接字_79


4.15 跳到CommandListener.cpp,反馈命令

4.15.1文件位置

system/vold/CommandListener.cpp

4.15.2 CommandListener::VolumeCmd::runCommand函数实现所有操作,反馈命令

Android5.0 外部磁盘管理(代码摘自google)_磁盘管理_80

五、Vold-FrameWork-UI 通信大结局
在Framework里面,有一个目录是用来存放一些Java的系统服务,这些都在后台跑着,在:/frameworks /base/services/java/com/android/server目录下,比较重要的是这两个源文件:MountService.java 和NativeDaemonConnector.java。
这里先列出在Vold中,VolumeCmd类处理的一些磁盘操作命令,这些命令均是有Framework下发的:
1.volume list:Framework先得到系统目前存在几个Volume对象,需要获取到这些对象的标签;
2.volume debug:设置USB调试模式
3.volume mount sdcard:挂载SD卡
4.volume unmount force:卸载SD卡
5.volume format sdcard:格式化SD卡
6.volume share sdcard ums:开启SD卡的OTG功能(大容量存储),也就是连接电脑
7.volume unshare sdcard ums:关闭SD卡的OTG功能(大容量存储)
8.volume shared sdcard ums:获取目前OTG的开启状态,就是是否连接电脑的状态
一下分别列出每个命令的下发函数

5.1 跳到NativeDaemonConnector.java,Framework磁盘管理服务的开启
 
在NativeDaemonConnector服务里面,开始监听底层Vold发送过来的磁盘热插拔事件的状态信息,当收到底层广播上来的状态,调用 MountService服务中的onDaemonConnected函数进行处理,当然这是开机第一次去获取信息的,也就是下发”volume list”命令

5.1.1文件位置

vi frameworks/base/services/core/java/com/android/server/NativeDaemonConnector.java

5.1.2 run(),listenToSocket()函数,主要用于内核监听事件

Android5.0 外部磁盘管理(代码摘自google)_套接字_81


Android5.0 外部磁盘管理(代码摘自google)_Android_82


5.1 跳到NativeDaemonConnector.java,Framework磁盘管理服务的开启

Android5.0 外部磁盘管理(代码摘自google)_磁盘管理_83


Android5.0 外部磁盘管理(代码摘自google)_初始化_84


以上两个比较重要的函数在MountService当中,处理相当多的内容,源码太长。

下发volume list命令,Framework收到反馈值,将调用onDaemonConnected函数获取到了磁盘的标签,挂载点与状态,然后调用doGetShareMethodAvailable函数判断现在是否连接OTG,若连接OTG,那么调用doShareUnshareVolume函数下发otg连接命令(volume share sdcard ums)。

5.2 跳到Volume.cpp ,Vold与Framework如何通信
onEvent主要是处理状态信息的解析,将每一种状态进行判断,并调用相应的操作函数。比如此时vold发送一个VolumeDiskInserted状态,意味着系统插入一个磁盘,于是onEvent就调用doMountVolume挂载函数进行下发命令(volume mount sdcard)。
在系统使用当中,用户可能会插入,移除,挂载,卸载,格式化磁盘,那么这儿多状态 如何告诉Framework呢?之前已经说过,vold使用了setState函数来广播磁盘的状态消息,使得Framework能够及时地判断下发什么 命令与操作。该函数在Volume.cpp源文件中,先贴出setState源码看看
5.2.1 文件位置
vi system/vold/Volume.cpp

5.2.2 setState()函数广播状态

Android5.0 外部磁盘管理(代码摘自google)_磁盘管理_85


可以看到,setState函数将磁盘的label,mountpoint,oldstate,statestr,newstate,statestr消 息通知给Framework,这样Framework就知道vold中SD卡的新旧状态。然后调用通过SocketListener类继承下来的 sendBroadcast函数广播消息,反馈码是ResponseCode::VolumeStateChange,代表状态改变的消息。

这里可能有个疑问,vold广播这么多消息,Framework是如何分清哪条消息是代表哪一类的反馈消息呢?

广播消息在开头使用了ResponseCode类提供的一些状态反馈码,每一类消息都用一个反馈码,这样Framework的MountService服务能够很快的判断出类型。之前的文章说过了,这里列出几个重要的反馈码:跟踪VolumeStateChange()得到反馈码

(文件位置:system/vold/ResponseCode,h)

Android5.0 外部磁盘管理(代码摘自google)_Android_86


setState函数只负责磁盘状态改变的广播,其他插入磁盘或者移除磁盘的都是直接调用sendBroadcast函数来广播,这里贴出插拔事件的广播函数:

5.3 UI根据信号相应的处理

从vold走到了Framework,最后一层就是UI,是用户操作磁盘的界面。我们都知道,在设置里面可以挂载,卸载与格式化SD卡。

UI的源码路径是:/packages/apps/Settings/src/com/android/settings/deviceinfo/Memory.java
我们可以发现,在Android手机的设置界面,或者主页面,只要插入SD卡或者移除SD卡,都会有相应的提示,

5.3.1 这些磁盘状态如何与UI通信的?
在MountService服务中,每改变状态,都会调用updatePublicVolumeState函数,可以理解:更新一个公用的磁盘状态,这里会设置到Environment类中的一个变量中,这样UI就能够取到磁盘的状态。

5.3.2 UI是如何调用FrameWork中的函数的?
前面提到过,UI 想要调用FrameWork中的MountService服务中的函数,比如以注册的方式得到调用操作磁盘函数的权限。

5.4跳到 SystemServer.java,系统启动时,调用MountService的构造函数
5.4.1 文件位置
vi frameworks/base/services/java/com/android/server/SystemServer.java

5.4.2 调用MountService()函数

Android5.0 外部磁盘管理(代码摘自google)_android_87


5.5 跳到MountService.java中,监听状态信息

上文我们分析到,SD卡被doMount方法执行挂载了,该消息由setState方 法将消息传递到上层,setState是通过发送一个广播,这里所说的广播不是Android中的BroadCast,这里实际山是Socket,上层负 责监听这个Socket,并解析其中的内容。我们需要从MountService.java开始查找。这里我要解释以下为什么要从这里开始找,不是说一开 始我就知道这个类里面有我们需要的东西,这是在查找SD卡挂载过程的时候,通过不同的线索联系起来的。那我们先来看看MountService吧。

5.5.1 文件位置

vi frameworks/base/services/java/com/android/server/MountService.java

5.5.2 MountService()函数,创建线程监听

Android5.0 外部磁盘管理(代码摘自google)_磁盘管理_88


Android5.0 外部磁盘管理(代码摘自google)_套接字_89


这里我们重点关注最后两句,这两句的意思我相信有一点java基础的人都知道吧,对,没 错,就是开启一个新线程,我继续跟踪这个传进来的Runnable对象mConnector,查看NativeDaemonConnector.java 后可以知道,该类实现了Runnable接口,同时也覆写了Runnable中的run()方法,在该方法中有一个死循环,主要负责监听来自Vold的 Socket消息,这是一个阻塞方法。

5.6跳到NativeDaemonConnector.java,寻找run()函数
5.6.1文件位置
vi frameworks/base/services/java/com/android/server/NativeDaemonConnector.java

5.6.2 run()函数,监听函数

Android5.0 外部磁盘管理(代码摘自google)_初始化_90


Android5.0 外部磁盘管理(代码摘自google)_套接字_91


Android5.0 外部磁盘管理(代码摘自google)_套接字_92


Android5.0 外部磁盘管理(代码摘自google)_android_93


5.7 跳到MountService.java,寻找onDaemonConnected()处理函数

5.7.1文件位置

vi ./frameworks/base/services/core/java/com/android/server/MountService.java

5.7.2 onDaemonConnected()函数实现

Android5.0 外部磁盘管理(代码摘自google)_Android_94


Android5.0 外部磁盘管理(代码摘自google)_初始化_95


这个函数里面首先执行 VoldResponseCode.VolumeListResult,

5.8跳到Memory.java,找到设置存储,从上到下分析

5.8.1 文件位置
vi ./packages/apps/Settings/src/com/android/settings/deviceinfo/Memory.java

5.8.2

Android5.0 外部磁盘管理(代码摘自google)_初始化_96

资料参考:
Android热插拔事件处理流程图

http://blog.sina.com.cn/s/blog_62dd461e0102v1xc.html

Android4.4—-Vold挂载管理分析(一)


Android磁盘管理-之vold源码分析


android SD卡自动挂载

SD卡 挂载分析Framework Android-vold源码分析之挂载SD卡(8)Android-Vold, Framework和UI的通信-大结局(12)

http://www.verydemo.com/demo_c131_i96079.html

Android 2.3 SD卡挂载流程浅析(一)



【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月25日 0

暂无评论

推荐阅读