AndroidSD卡挂载流程浅析.docx
《AndroidSD卡挂载流程浅析.docx》由会员分享,可在线阅读,更多相关《AndroidSD卡挂载流程浅析.docx(102页珍藏版)》请在冰豆网上搜索。
AndroidSD卡挂载流程浅析
Android2.3中关于SD卡挂载简介
在Android2.3中,当SD卡插入系统之后,系统会自动挂载。
Vold就是负责挂载SD卡的,vold的全称是volumedaemon。
实际上是负责完成系统的CDROM,USB大容量存储,MMC卡(后文有简介,具体请XX)等扩展存储的挂载任务自动完成的守护进程。
它提供的主要特点是支持这些存储外设的热插拔。
在Android上的这个vold系统和GNU/Linux的之间存在很大的差异。
自Android2.2开始,vold又做了大改动,升级为vold2.0,之前的配置文件是system/etc/vold.conf,vold2.0变为system/etc/vold.fstab。
vold.fstab中的内容显示如下:
dev_mountsdcard/mnt/sdcardauto/devices/platform/goldfish_mmc.0/devices/platform/msm_sdcc.2/mmc_host/mmc1
##Exampleofadualcardsetup
#dev_mountleft_sdcard /sdcard1 auto/devices/platform/goldfish_mmc.0/devices/platform/msm_sdcc.2/mmc_host/mmc1
#dev_mountright_sdcard/sdcard2 auto/devices/platform/goldfish_mmc.1/devices/platform/msm_sdcc.3/mmc_host/mmc1
##Exampleofspecifyingaspecificpartitionformounts
#dev_mountsdcard/sdcard2/devices/platform/goldfish_mmc.0/devices/platform/msm_sdcc.2/mmc_host/mmc1
可以看到大部分是注释,最重要的为以下这句:
dev_mountsdcard/mnt/sdcardauto/devices/platform/goldfish_mmc.0/devices/platform/msm_sdcc.2/mmc_host/mmc1
这句代码意思是:
外置SD卡的挂载路径,auto代表挂载SD卡的第一个分区,后面是vold监测的路径,当插入sd时,/devices/platform/msm_sdcc.2/mmc_host/mmc1路径下会多出一个文件夹,在该文件夹中包含了SD卡的各种ID信息,以及生产日期等。
如果把sd卡插入设备,在/dev/block/目录下面也会多出几个设备节点,证明sd卡的驱动已经成功加载。
我自己测试的目录下面会形成mmcblk0 和mmcblk0p1节点,注意:
这两个节点的意思,mmcblk0代表第一个SD卡设备,mmcblk0p1代表第一个SD卡设备的第一个分区。
真正挂载到系统中的是mmcblk0p1而不是mmcblk0,这一点很重要。
PS:
MMC(MultiMediaCard)卡由西门子公司和首推CF的SanDisk于1997年推出。
1998年1月十四家公司联合成立了MMC协会(MultiMediaCardAssociation简称MMCA),现在已经有超过84个成员。
MMC的发展目标主要是针对数码影像、音乐、手机、PDA、电子书、玩具等产品,号称是目前世界上最小的FlashMemory存贮卡,尺寸只有32mmx24mmx1.4mm。
虽然比SmartMedia厚,但整体体积却比SmartMedia小,而且也比SmartMedia轻,只有1.5克。
MMC也是把存贮单元和控制器一同做到了卡上,智能的控制器使得MMC保证兼容性和灵活性。
MMC_XX百科
SD/MMC卡的设备构造差不多,不过MMC当时的设计比SD小一半。
所以,SD/MMC的驱动通用,进一步的,Linux的设备节点就延续了MMC的这个名字,后面的blk是块设备这个英文的简写,mmcblk也就是“mmc/sd块设备”,0就是这个mmc/sd设备的顺序编号,p1就是第一个分区。
挂载流程简析
内核层(kernel):
当有新的SD/USB设备插入时,kernel将自动检测并加载对应的驱动,同时kernel中的sysfs机制会在有新的驱动加载时给用户层发送相应的event,然后将kernel产生的这些event传递给vold。
用户层(user):
用户层通过sysfs可以接收来自kernel的uevent,这些收到的信息可以在/sys/block/mmcblk0下用命令cat*来查看,如:
#cat*
bdi:
invalidlength
10
179:
0
device:
invalidlength
8
holders:
invalidlength
power:
invalidlength
queue:
invalidlength
8
0
0
524288
slaves:
invalidlength
278 813 8686 1050 0 0 0 0 0 240 1040
subsystem:
invalidlength
MAJOR=179
MINOR=0
DEVTYPE=disk
NPARTS=0
#
如果这时候在终端输入"pwd"指令,大家会发现路径并不是我们之前进入的路径/sys/block/mmcblk0,而是/sys/devices/platform/goldfish_mmc.0/mmc_host/mmc0/mmc0:
e118/block/mmcblk0。
其中mmc0:
e118这个文件是插入SD卡之后生成的文件。
Sysfs传递来的是一个多行的文档,vold需要解析这个文档。
Vold将处理之后的事件传递给MountService,然后MoutService会将信息进一步处理传递给StorageManager,最后我们可以在系统设置界面看到SD卡挂载成功的信息,这包括了SD卡的总容量以及可用空间如下图:
SD卡的挂载流程大致如此,MountServie实际上还会通知PackageManagerService,因为这里分析的是SD卡挂载从底层到上层的表现,因此这里暂不分析。
简约流程图如下:
在上一篇博文《Android2.3SD卡挂载流程浅析
(一)》主要简单的介绍了SD卡的挂载流程。
包括了从内核层到用户层事件消息的传递,以及Vold的简介。
本文将继续介绍SD卡的挂载,但文中并不会涉及代码的详细分析,因为这部分网上已有资料,我会在文章结尾贴出来供大家参考。
本文主要目的是一方面对自己学习这一部分的总结,另一方面希望大家能够指出文中理解错误的地方。
1.SD卡挂载流程图
SD卡的挂载流程图如下:
绿色箭头:
表示插入SD卡后事件传递以及SD卡挂载
红色箭头:
表示挂载成功后的消息传递流程
黄色箭头:
表示MountService发出挂载/卸载SD卡的命令
大家可能对图中突然出现的这么多的名称感到奇怪,这些都是在Android2.3源码中可以找到的,接下来我会为大家一一解释这些类的作用。
2.各个文件的主要作用
(1)Kernel:
这个是系统内核啦。
不是我要分析的文件,本文涉及内容不是内核级的哦!
(努力学习中...)
(2)NetlinkManager:
全称是NetlinkManager.cpp位于Android2.3源码位置/system/vold/NetlinkManager.cpp。
该类的主要通过引用NetlinkHandler类中的onEvent()方法来接收来自内核的事件消息,NetlinkHandler位于/system/vold/NetlinkHandler.cpp。
(3)VolumeManager:
全称是VolumeManager.cpp位于Android2.3源码位置/system/vold/VolumeManager.cpp。
该类的主要作用是接收经过NetlinkManager处理过后的事件消息。
因为我们这里是SD卡的挂载,因此经过NetlinkManager处理过后的消息会分为五种,分别是:
block,switch,usb_composite,battery,power_supply。
这里SD卡挂载的事件是block。
(4)DirectVolume:
位于/system/vold/DirectVolume.cpp。
该类的是一个工具类,主要负责对传入的事件进行进一步的处理,block事件又可以分为:
Add,Removed,Change,Noaction这四种。
后文通过介绍Add事件展开。
(5)Volume:
Volume.cpp位于/system/vold/Volume.cpp,该类是负责SD卡挂载的主要类。
Volume.cpp主要负责检查SD卡格式,以及对复合要求的SD卡进行挂载,并通过Socket将消息SD卡挂载的消息传递给NativeDaemonConnector。
(8)StorageManaer:
位于frameworks/base/core/java/andriod/os/storage/StorageManager.java。
在该类的说明中有提到,该类是系统存储服务的接口。
在系统设置中,有Storage相关项,同时Setting也注册了该类的监听器。
而StorageManager又将自己的监听器注册到了MountService中,因此该类主要用于上层应用获取SD卡状态。
通过上文对各个文件的作用简介,以及整个SD卡的挂载流程图可以知道,Android系统是如何从底层获取SD卡挂载信息的。
后文将继续分析程序调用流程图。
在前面两篇博文《Android2.3SD卡挂载流程浅析
(一)》《Android2.3SD卡挂载流程浅析
(二)》中,主要简单介绍了SD卡的挂载流程以及所涉及的关键文件。
在《Android2.3SD卡挂载流程浅析(三)》中,将简要介绍Android2.3中Vold的运行机制,并从接收内核uevent开始介绍程序调用流程。
1.Vold
Vold的全称是volumedaemon。
主要负责系统对大容量存储设备(USB/SD)的挂载/卸载任务,它是一个守护进程,该进程支持这些存储外设的热插拔。
自Android2.2开始,Vold升级为vold2.0,之前的配置文件路径在system/etc/vold.conf,Android2.3之后变为system/etc/vold.fstab。
2.Vold工作流程
Vold的工作流程大致可以分为三个部分:
创建监听、引导、事件处理。
(1)创建监听
创建监听指的是创建监听链接,一方面用于监听来自内核的uevent,另一方面用于监听来自上层的控制命令,这些命令包括控制SD卡的挂载与卸载,这里所说的链接也就是Socket。
在Android系统启动的时候,init进程会去解析init.rc文件,在该文件中,有如下代码:
Servicevold/system/bin/vold
Socketvoldstream0660rootmount
Ipriobe2
这样系统会在启动的时候创建与上层通信的Socket。
在Android2.3源码/system/vold路径下的main.cpp中创建了与内核通信的Socket。
在main.cpp中通过实例化VolumeManager和NetlinkManager时创建。
(2)引导
Vold进程启动时候会对现有的外部存储设备进行检查。
首先加载并解析vold.fstab,并检查挂载点是否已被挂载。
然后执行SD卡的挂载,最后处理USB大容量存储。
因为系统是按行解析的,通过查看vold.fstab可以很清楚的知道这一点。
vold.fatab中最重要的语句:
dev_mount sdcard /mnt/sdcard auto /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1
dev_mount
挂载命令 标签 挂载点 子分区个数 挂载路径
注:
子分区个数如果为auto则表示只有1个子分区,也可以为任何不为0的整数。
参数之间不能有空格,只能以tab为间隔(注意:
这里为了对齐因此采用空格隔开,如果自行修改vold.fstab之后加以空格的话系统会识别不到的)。
如果vold.fstab解析无误,VolueManager将创建DirectVolume,若vold.fstab解析不存在或者打开失败,Vold将会读取Linux内核中的参数,此时如果参数中存在SDCARD(也就是SD的默认路径),VolumeManager则会创建AutoVolume,如果不存在这个默认路径那么就不会创建。
(3)事件处理
通过对两个socket的监听,完成对事件的处理以及对上层应用的响应。
a. Kernel发出uevent
NetlinkManager检测到kernel发出的uevent,解析后调用NetlinkHandler:
:
onEvent()方法。
该方法会分别处理不同的事件,这里重要的事件有:
“block”事件主要指Volume的mount、unmount、createAsec等。
由VolumeManager的handleBlockEvent(evt)来处理,根据多态性最终将会调用AutoVolume或者DirectVolume的handleBlockEvent方法来处理。
“switch”事件主要指Volume的connet、disconnet等。
根据相关操作,改变设备参数(设备类型、挂载点等)通过CommandListener告知FrameWork层。
b. FrameWork发出控制命令
与a相反,CommandListener检测到FrameWork层的命令(MountService发出的命令)调用VolumeManager的函数,VolumeManager找出对应的Volume,调用Volume函数去挂载/卸载操作。
而Volume类中的相关操作最终通过调用Linux函数完成。
这里再次贴上这张流程图:
3.SD卡挂载流程代码浅析
这里只是简要的分析SD卡挂载过程中重要的代码调用,并没有深入分析代码,因为这一部分网上已有牛人比较详尽的分析了,后面我会贴出这些参考文章。
整个过程从Kernel检测到SD卡插入事件开始,之前的一些硬件中断的触发以及driver的加载这里并不叙述,一直到SD卡挂载消息更新到“Android——系统设置——存储”一项中。
1. Kernel发出SD卡插入uevent。
2. NetlinkHandler:
:
onEvent()接收内核发出的uevent并进行解析。
3. VolumeManager:
:
handlBlockEvent()处理经过第二步处理后的事件。
4. 接下来调用DirectVolume:
:
handleBlockEvent()。
在该方法中主要有两点需要注意:
第一,程序首先会遍历mPath容器,寻找与event对应的sysfs_path是否存在与mPath容器中。
第二,针对event中的action有4种处理方式:
Add,Removed,Change,Noaction。
例如:
在Addaction中会有如下操作(因为我们这里所讲的是SD卡的挂载流程,因此以Add来说明),首先创建设备节点,其次对disk和partition两种格式的设备分别进行处理。
SD卡属于disk类型。
5. 经过上一步之后会调用DirectVolume:
:
handleDiskAdded()方法,在该方法中会广播diskinsert消息。
6. SocketListener:
:
runListener会接收DirectVolume:
:
handleDiskAdded()广播的消息。
该方法主要完成对event中数据的获取,通过Socket。
(PS:
这里的SocketListener.cpp位于Android源码/system/core/libsysutils/src/中,后文的FramworkListener.cpp也是,之前自己找了很久T_T)
7. 调用FrameworkListener:
:
onDataAvailable()方法处理接收到的消息内容。
8. FrameworkListener:
:
dispatchCommand()该方法用于分发指令。
9. 在FrameworkListener:
:
dispatchCommand()方法中,通过runCommand()方法去调用相应的指令。
10. 在/system/vold/CommandListener.cpp中有runCommand()的具体实现。
在该类中可以找到这个方法:
CommandListener:
:
VolumeCmd:
:
runCommand(),从字面意思上来看这个方法就是对Volume分发指令的解析。
该方法中会执行“mount”函数:
vm->mountVolume(arg[2])。
11. mountVolume(arg[2])在VolumeManager:
:
mountVolume()中实现,在该方法中调用v->mountVol()。
12. mountVol()方法在Volume:
:
mountVol()中实现,该函数是真正的挂载函数。
(在该方法中,后续的处理都在该方法中,在Mount过程中会广播相应的消息给上层,通过setState()函数。
)
13. setState(Volume:
:
Checking);广播给上层,正在检查SD卡,为挂载做准备。
14. Fat:
:
check();SD卡检查方法,检查SD卡是否是FAT格式。
15. Fat:
:
doMount()挂载SD卡。
至此,SD的挂载已算初步完成,接下来应该将SD卡挂载后的消息发送给上层,在13中也提到过,在挂载以及检查的过程中其实也有发送消息给上层的。
16. MountService的构造函数中会开启监听线程,用于监听来自vold的socket信息。
Threadthread=newThread(mConnector,VOLD_TAG);thread.start();
17. mConnector是NativeDaemonConnector的对象,NativeDaemonConnector继承了Runnable并Override了run方法。
在run方法中通过一个while(true)调用ListenToSocket()方法来实现实时监听。
18. 在ListenToSocket()中,首先建立与Vold通信的SocketServer端,然后调用MountService中的onDaemonConnected()方法。
(PS:
Java与Native通信可以通过JNI,那么Native与Java通信就需要通过Socket来实现了。
Android中Native与Frameworks通信
前面的三篇博文《Android2.3SD卡挂载流程浅析
(一)》、《Android2.3SD卡挂载流程浅析
(二)》、《Android2.3SD卡挂载流程浅析(三)》的分析,知道了SD卡挂载的消息是如何从底层传递到上层的,在《Android2.3SD卡挂载流程浅析(三)》中,我们已经知道了最后是在updatePublicVolumeState()中调用onStorageStateChanged(),从而达到更新SD卡挂载信息的。
在本文《Android2.3SD卡挂载流程浅析(四)》中,我会将前文提到的程序调用流程图画出来,并对代码进行简单的分析。
首先,还是挂出这张老图(因为每次都用这张图0_0...)。
就权当复习吧,这是SD卡的整个挂载流程,而程序的调用也是根据这个流程图来的。
1.接收并处理uevent
首先是接收因为插入SD卡被内核检测到而发出的Event;
NetlinkHandler:
:
onEvent(NetlinkEvent*evt)
//代码路径:
AndroidSourcecode2.3/system/vold/NetlinkHandler.cpp
//该方法主要通过evt->getSubsystem();方法来获取系统的event
viewplain
1.void NetlinkHandler:
:
onEvent(NetlinkEvent *evt) {
2. VolumeManager *vm = VolumeManager:
:
Instance();
3. const char *subsys = evt->getSubsystem();
4. if (!
subsys) {
5. SLOGW("No subsystem found in netlink event");
6. return;
7. }
8. if (!
strcmp(subsys, "block")) {
9. vm->handleBlockEvent(evt);
10. } else if (!
strcmp(subsys, "switch")) {
11. vm->handl