你的位置:首页 > 操作系统

[操作系统]Android的存储系统—Vold与MountService分析(一)


Android的存储系统(一)

看了很长时间Vold存储模块的相关知识,也死扣了一段时间的Android源码,发现Android存储系统所涉及的函数调用,以及Kernel与上层之间的Socket传输真的是让人头疼,除了需要整理整个架构的原理以外,还要反复看源码,真真的郁闷。

郁闷之余,还是打算把自己看过的经验之贴和参考资料进行整理,以帖子的形式发出来,供码神们参考,有不对的地方请指正,我们互相交流,下面就进入主题。

Android的存储系统主要由:SystemServer进程中的MountService和Vold进程中的VolumeManager组成。

它们管理着系统的存储设备,执行各种操作,如:mount、unmount、format等。

图1 Android存储系统架构图

图2 Android存储系统原理图

【重要组成分析】

1、NetlinkManager

     全称是NetlinkManager.cpp位于Android 4.x 源码位置/system/vold/NetlinkManager.cpp。

     该类的主要通过引用NetlinkHandler类中的onEvent()方法来接收来自内核的事件消息,NetlinkHandler位于/system/vold/NetlinkHandler.cpp。

2、VolumeManager

     全称是VolumeManager.cpp位于Android 4.x源码位置/system/vold/VolumeManager.cpp。该类的主要作用是接收经过NetlinkManager处理过后的事件消息。

     因为我们这里是SD的挂载,因此经过NetlinkManager处理过后的消息会分为五种,分别是:block、switch、usb_composite、battery、power_supply。

     这里SD卡挂载的事件是block。

3、DirectVolume

     位于/system/vold/DirectVolume.cpp。该类的是一个工具类,主要负责对传入的事件进行进一步的处理。

     block事件又可以分为:Add、Removed、Change、Noaction这四种。

4、Volume

     位于/system/vold/Volume.cpp,该类是负责SD卡挂载的主要类。Volume.cpp主要负责检查SD卡格式,以及对复合要求的SD卡进行挂载,并通过Socket将消息SD卡挂载的消息传递给NativeDaemonConnector。

5、CommandListener

     该类位于位于/system/vold/CommandListener.cpp,通过vold socket与NativeDaemonConnector通信。

6、NativeDaemonConnector

     该类位于frameworks/base/services/java/com.android.server/NativeDaemonConnector.java。该类用于接收来自Volume.cpp 发来的SD卡挂载消息并向上传递。

7、MountService

     位于frameworks/base/services/java/com.android.server/MountService.java。

     MountService是一个服务类,该服务是系统服务,提供对外部存储设备的管理、查询等。在外部存储设备状态发生变化的时候,该类会发出相应的通知给上层应用。在Android系统中这是一个非常重要的类。

8、StorageManaer

     位于frameworks/base/core/java/andriod/os/storage/StorageManager.java。

     在该类的说明中有提到,该类是系统存储服务的接口。在系统设置中,有Storage相关项,同时Setting也注册了该类的监听器。

     而StorageManager又将自己的监听器注册到了MountService中,因此该类主要用于上层应用获取SD卡状态。

 

【SD卡挂载流程】

1、Kernel发出SD卡插入uevent消息。

2、NetlinkHandler::onEvent()接收内核发出的uevent并进行解析。

3、VolumeManager::handleBlockEvent()处理经过第二步处理后的事件。

4、接下来调用DirectVolume::handleBlockEvent()。

在该方法中需要注意亮点:

(1)程序首先会遍历mPath容器,寻找与event对应的sysfs_path是否存在于mPath容器中;

(2)针对event中的action有4种处理方式:Add、Removed、Change、Noaction。

 

 

 

5、经过上一步之后会调用DirectVolume::handleDiskAdded()方法,该方法中会广播disk insert消息。

6、SocketListener::runListener()会接收DirectVolume::handleDiskAdded()广播的消息。该方法主要完成对event中数据的获取,通过Socket。

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信息。

     Thread thread = new Thread(mConnector,VOLD_TAG); thread.start();

17、mConnector是NativeDaemonConnector的对象,NativeDaemonConnector继承了Runnable并Override了run方法。在run方法中通过一个while(true)调用ListenToSocket()方法来实现实时监听。

18、在ListenToSocket()中,首先建立与Vold通信的Socket Server端,然后调用MountService中的onDaemonConnected()方法。

19、onDaemonConnected()方法是在接口INativeDaemonConnectorCallbacks中定义的,MountService实现了该接口并Override了onDaemonConnected()方法。该方法开启一个线程用于更新外置存储设备的状态,主要更新状态的方法也在其中实现。

20、然后回到ListenToSocket中,通过inputStream来获取Vold传递来的event,并存放在队列中。

21、然后这些event会在onDaemonConnected()通过队列的”队列.take()”方法取出。并根据不同的event调用updatePublicVolumeState()方法,在该方法中调用packageManagerService中的updateExteralState()方法来更新存储设备的状态。

22、更新是通过packageHelper.getMountService().finishMediaUpdate()方法来实现的。

23、在updatePublicVolumeState()方法中,更新后会执行如下代码:

       bl.mListener.onStorageStateChanged();

在Android源码/packages/apps/Settings/src/com.android.settings.deviceinfo/Memory.java代码中,实现了StorageEventListener 的匿名内部类,并Override了onStorageStateChanged()方法。因此在updatePublicVolumeState()中调用onStorageStateChanged()方法后,Memory.java中也会收到。在Memory.java中收到以后会在Setting界面进行更新,系统设置—存储中会更新SD卡的状态。从而SD卡的挂载从底层到达了上层。

 

在下一个帖子中我会对Vold模块的源码以及MountService服务进行分析,包括main函数、NetlinkManager、NetlinkHandler、处理block类型的uevent、处理MountService命令、VolumeManager、NativeDaemonConnector等源码,很快就会与大家见面,感谢支持,欢迎交流与指正!