Jimmy Chen

A Programmer

(原创)根据log分析SD卡挂载过程

  在分析SD卡挂载过程前,先了解Android存储的一些杂乱概念吧。

Android存储类型

Internal vs External

  对于Internal Storage 与 External Storage,官方文档上有这么一段话,描述得很详细了,我翻译了一段下来:

  所有的Android设备都有两块存储区域:Internal Storage和External Storage。它们的名称来源于早期的Android系统,那时候大家的手机都内置(Permanent)一块较小存储板(即Internal Storage),并配上一个的外置的(Removable)储存卡(即External Storage)。后来部分手机开始将最初定义的“Internal Storage”,即内置存储,分成Internal和External两部分。这样一来就算没有外置储存,手机也有Internal和External两块存储区域。这两块存储区域的区别是:

Internal Storage:

External Storage:

注:此处讨论的访问权限是应用路径下的权限。

总结下来,External存储区域有几个好处:

  1. 可以传到电脑上;
  2. 可以与其他app共享;
  3. 在4.4之后的App路径(Android/data/包名)下读写不需任何权限;
  4. 存在App路径之外的文件不会随App卸载。

相应的,也有几个缺点:

  1. 可能不可用;
  2. 会被其他应用读到;
  3. 在非App路径下写、修改文件需要权限。

Primary vs Secondary

  这个Primary和Secondary是怎么来的呢?实际上最开始Android也没有考虑这个区分,但是后来有一个情况发生了,就是上面所说到的:

后来部分手机开始将最初定义的“Internal Storage”,即内置存储,分成Internal和External两部分。

  那么如果这个时候手机再插入sd卡,那不是有多个External Storage了吗?

  这个时候,从Internal Storage里面分出来的那块“External Storage”我们称之为主存储(Primary Storage),插入的外置储存称之为副存储(Secondary Storage)。

  副存储路径在4.4及以上的Android系统中,可以使用Context.getExternalFilesDirs(null)(注意最后多了一个’s’),它返回的是一个字符串数组。第0个就是主存储路径,第1个是副存储路径(如果有的话)。

注:以上内容转载自:https://blog.csdn.net/tanranran/article/details/51386106

Adaptable Storage

  Adoptable Storage Devices使系统获得了更大的存储容量,并且使用户可以自由移动应用和隐私数据到外部存储设备,不在需要第三方工具。用户使用Android设备时,可以主动的选择把外部存储设备格式化为常规移动存储或者系统内部存储。在格式化时系统给了两种选择:(1)Use as portable storage(for moving photos and other media between divices),仅仅作为外部存储设备;(2)Use as internal storage(for storing anything on this device only,including apps and photos),包裹一个加密层后,能够作为内部存储空间存储应用和隐私数据,经过加密后,该存储设备就不能再被别的设备使用。

底层处过程

  下面是插入SD卡后截取的logcat main log信息:

  至于最底层内核驱动上报插入SD卡部分这里就不分析了。我们直接从NetlinkHandler::onEvent()接收到插入SD卡事件通知开始。

NetlinkHandler::onEvent

  NetlinkHandler::onEvent方法存在两个NetlinkHandler.cpp文件中,这里我们涉及的是vold下的NetlinkHandler::onEvent

此处对底层过滤选择底层上报的事件,具体是处理block事件

VolumeManager::handleBlockEvent

Disk::Disk

调用Disk类的构造函数后,接着就调用Disk类的create方法,接下来我们看看create的实现。

Disk::create

  首先发出DiskCreated事件通知,对应的log就是上面贴出的main log的第一句:

Disk::readMetadata

上面代码中最后三个事件通知对应下面main log信息:

从log中获取到的信息为,mSize=15836643328,mLabel为空,mSysPath为/sys//devices/soc/7864900.sdhci/mmc_host/mmc1/mmc1:59b4/block/mmcblk1

Disk::readPartitions

执行sgdisk过程输出的log信息如下:

其中DISK mbrPART 1 c是执行sgdisk的返回值。

最后调用Disk::createPublicVolume来创建Volume,下面接着分析Volume的创建过程

Disk::createPublicVolume

setDiskId没什么好分析的,接下来分析create方法

VolumeBase::create

volumeCreated事件通知对应如下log:

到这里Volume相关操作就完成了,这里返回到Disk::readPartitions方法中,Disk::readPartitions最后会发出一个Disk::readPartitions事件通知,对应的log如下:

StorageManagerService处理过程

  底层中通过notifyEvent发出的事件,在上次会通过StorageManagerService::onEventLocked来进行统一处理

StorageManagerService::onEventLocked

上面只添加了到目前为止遇到的log信息,之后再mount的时候还会有新的event log信息,到后面遇到再添加分析。这里我们主要看VOLUME_CREATED相关的内容,VOLUME_CREATED相关操作主要是通过调用onVolumeCreatedLocked来创建volume

StorageManagerService::onVolumeCreatedLocked

我们这里mount的是PUBLIC设备,所以其余部分就省略了,另外从代码中看,也只是设置了一些标识位,这里较多关于Adoptable存储的相关设置的,可惜设备使用的是FBE,所以这里不能使用Adoptable存储方式,这样也就会导致MOUNT_FLAG_VISIBLE为也会被设置为false。导致通过MTP在PC端或者其他的FileManager APP都无法查看SD卡内的文件。最后通过mHandler发出H_VOLUME_MOUNT。

H_VOLUME_MOUNT处理

继续忽略不相关部分,只做主要的分析。这里其实也简单,只是通过mConnect,给vold发送相关指令,告诉vold需要需要执行什么操作而已。这个指令通过socket最终由vold的CommandListener::VolumeCmd::runCommand来处理,这行代码对应的log如下:

CommandListener::VolumeCmd::runCommand

在此之前,我们创建过PublicVolume类型的变量,并添加到链表里面了,这里取出之前创建的PublicVolume类型的变量。并调用其mount方法,但是因为PublicVolume没有实现mount方法,所以这里调用的是基类VolumeBase的mount方法。

VolumeBase::mount

PublicVolume::doMount

PublicVolume::readMetadata

readMetadata完成两件事,首先调用Utils.cpp中的ReadMetadataUntrusted方法,而后者继续调用Utils.cpp的readMetadata;其次调用notifyEvent发出三个事件通知,对应的log如下:

Utils::readMetadata

readMetadata执行blkid的相应log信息如下:

到这里readMetadata方法的执行就结束了。接下来我们继续看doMount中关键的第二个方法vfat::Check

vFat::Check

上面执行对应的log如下:

至于fsck_msdos所完成的工作就不在此文讨论,有兴趣的朋友可以在网上搜到相关资料,后续有机会再分析。接下来我们接着看doMount后面的内容,下面就到设置路径了:

VolumeBase::setInternalPath

对应log:

VolumeBase::setPath

对应log:

接下来继续回到doMount,下面就到vfat:Mount了

vfat::Mount

其实到这里挂载成功的话,后续也就没有必要分析了。基本就是挂载成功后的一些收尾工作,后面的博主就不打算接着分析了,基本也是贴代码和log,大家应该也看得吃劲。有什么其他的问题,大家可以给我留言交流。

  1. lion_heart说道:

    楼主,请教一个问题,我想挂载内部存储开机为只读文件系统,需要修改什么地方呢?

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注