外部存储由 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
:可选的逗号分隔的标志列表,不得包含/
。可能的值包括nonremovable
和encryptable
。
对于 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_flags
:Vold
忽略此字段,应将其设置为defaults
fs_mgr_flags
:Vold
忽略统一 fstab 中不包含此字段中的voldmanaged=
标志的任何行。此标志后面必须跟一个描述卡的标签,以及一个分区号或单词auto
。这是一个示例:voldmanaged=sdcard:auto
。其他可能的标志包括nonremovable
、encryptable=sdcard
、noemulatedsd
和encryptable=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
是不同的文件。)
- 开发人员可以继续根据其用例动态或静态地构建路径。在路径中包含 UUID 可以标识每个卡,从而使开发人员更清楚地了解位置。(例如,
- 硬编码的 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 加密,并使用ext4
或f2fs
格式化,具体取决于内核功能。分区类型 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
检测文件系统类型,并且当文件系统不受支持时,用户可以选择格式化媒体。