设备配置

外部存储由 vold init 服务和 StorageManagerService 系统服务的组合管理。物理外部存储卷的挂载由 vold 处理,它执行暂存操作以准备媒体,然后再将其暴露给应用。

注意: 在 Android 8.0 中,MountService 类被重命名为 StorageManagerService

文件映射

对于 Android 4.2.2 及更早版本,设备特定的 vold.fstab 配置文件定义了从 sysfs 设备到文件系统挂载点的映射,并且每行都遵循以下格式

dev_mount <label> <mount_point> <partition> <sysfs_path> [flags]
  • label:卷的标签。
  • mount_point:卷应挂载到的文件系统路径。
  • partition:分区号(从 1 开始),或 'auto' 表示第一个可用的分区。
  • sysfs_path:一个或多个 sysfs 路径,指向可以提供此挂载点的设备。用空格分隔,并且每个路径都必须以 / 开头。
  • flags:可选的逗号分隔的标志列表,不得包含 /。可能的值包括 nonremovableencryptable

对于 Android 4.3 及更高版本,init、vold 和 recovery 使用的各种 fstab 文件统一在 /fstab.<device> 文件中。对于由 vold 管理的外部存储卷,条目应具有以下格式

<src> <mnt_point> <type> <mnt_flags> <fs_mgr_flags>
  • src:sysfs 下(通常挂载在 /sys)指向可以提供挂载点的设备的路径。路径必须以 / 开头。
  • mount_point:卷应挂载到的文件系统路径。
  • type:卷上的文件系统类型。对于外部卡,这通常是 vfat
  • mnt_flagsVold 忽略此字段,应将其设置为 defaults
  • fs_mgr_flagsVold 忽略统一 fstab 中不包含此字段中的 voldmanaged= 标志的任何行。此标志后面必须跟一个描述卡的标签,以及一个分区号或单词 auto。这是一个示例:voldmanaged=sdcard:auto。其他可能的标志包括 nonremovableencryptable=sdcardnoemulatedsdencryptable=userdata

配置详情

框架级别及以上的外部存储交互由 StorageManagerService 处理。由于 Android 6.0 中的配置更改(例如删除了 storage_list.xml 资源覆盖),配置详情分为两类。

Android 5.x 及更早版本

设备特定的 storage_list.xml 配置文件(通常通过 frameworks/base 覆盖提供)定义了存储设备的属性和约束。<StorageList> 元素包含一个或多个 <storage> 元素,其中恰好一个应标记为 primary。<storage> 属性包括

  • mountPoint:此挂载的文件系统路径。
  • storageDescription:描述此挂载的字符串资源。
  • primary:如果此挂载是主外部存储,则为 true。
  • removable:如果此挂载具有可移动媒体(例如物理 SD 卡),则为 true。
  • emulated:如果此挂载是模拟的,并且由内部存储支持(可能使用 FUSE 守护程序),则为 true。
  • mtp-reserve:MTP 应为可用存储保留的存储空间 MB 数。仅当挂载标记为 emulated 时使用。
  • allowMassStorage:如果此挂载可以通过 USB 大容量存储共享,则为 true。
  • maxFileSize:最大文件大小,单位为 MB。

设备可以通过模拟由内部存储支持的不区分大小写、无权限的文件系统来提供外部存储。一种可能的实现方式是由 system/core/sdcard 中的 FUSE 守护程序提供,可以将其添加为设备特定的 init.rc 服务

# virtual sdcard daemon running as media_rw (1023)
service sdcard /system/bin/sdcard <source_path> <dest_path> 1023 1023
    class late_start

其中 source_path 是后备内部存储,dest_path 是目标挂载点。

在配置设备特定的 init.rc 脚本时,EXTERNAL_STORAGE 环境变量必须定义为主外部存储的路径。/sdcard 路径也必须解析为相同的位置,可能通过符号链接。如果设备在平台更新之间调整了外部存储的位置,则应创建符号链接,以便旧路径继续工作。

Android 6.0

存储子系统的配置现在集中在设备特定的 fstab 文件中,并且为了支持更动态的行为,已删除了一些历史静态配置文件/变量

  • storage_list.xml 资源覆盖已被删除,框架不再使用。现在,存储设备在被 vold 检测到时动态配置。
  • EMULATED_STORAGE_SOURCE/TARGET 环境变量已被删除,Zygote 不再使用它们来配置用户特定的挂载点。相反,现在使用用户特定的 GID 来强制执行用户隔离,并且主共享存储在运行时由 vold 挂载到位。
    • 开发人员可以继续根据其用例动态或静态地构建路径。在路径中包含 UUID 可以标识每个卡,从而使开发人员更清楚地了解位置。(例如,/storage/ABCD-1234/report.txt 显然与 /storage/DCBA-4321/report.txt 是不同的文件。)
  • 硬编码的 FUSE 服务已从设备特定的 init.rc 文件中删除,而是在需要时从 vold 动态派生。

除了这些配置更改之外,Android 6.0 还引入了可采纳存储的概念。对于 Android 6.0 设备,任何未被采纳的物理介质都被视为便携式存储。

可采纳的存储设备

要在 fstab 中指示可采纳存储设备,请在 fs_mgr_flags 字段中使用 encryptable=userdata 属性。这是一个典型的定义

/devices/platform/mtk-msdc.1/mmc_host*           auto      auto     defaults
voldmanaged=sdcard1:auto,encryptable=userdata

当存储设备被采纳时,平台会擦除内容并写入 GUID 分区表,该表定义了两个分区

  • 一个小型的空 android_meta 分区,保留供将来使用。分区类型 GUID 为 19A710A2-B3CA-11E4-B026-10604B889DCF。
  • 一个大的 android_ext 分区,使用 dm-crypt 加密,并使用 ext4f2fs 格式化,具体取决于内核功能。分区类型 GUID 为 193D1EA4-B3CA-11E4-B075-10604B889DCF。

便携式存储

fstab 中,具有 voldmanaged 属性的存储设备默认被视为便携式存储,除非定义了另一个属性(如 encryptable=userdata)。例如,这是 USB OTG 设备的典型定义

/devices/*/xhci-hcd.0.auto/usb*             auto            auto    defaults
                                                    voldmanaged=usb:auto

平台在挂载前使用 blkid 检测文件系统类型,并且当文件系统不受支持时,用户可以选择格式化媒体。