Android 一直都支持外部存储配件(如 SD 卡),但由于这些配件存在预期的无常性,以及传统外部存储设备只受最低限度的数据保护,因此这些配件一直以来仅限于进行简单的文件存储。Android 6.0 推出了合并外部存储媒介(使其可以像内部存储设备一样使用)的功能。

当合并外部存储媒介时,系统将对其进行格式化和加密处理,以便一次只在一台 Android 设备上使用。由于该媒介与合并它的 Android 设备紧密关联,因此可以安全地为所有用户存储应用和私密数据。

当用户将新的存储媒介(如 SD卡)插入到可合并的位置时,Android 会询问他们想要如何使用该媒介。他们可以选择合并该媒介,这样的话,系统会对该媒介进行格式化和加密处理,或者也可以继续按原样将其用于简单的文件存储。如果他们选择合并媒介,平台会询问是否将主要共享存储内容(通常装载在 /sdcard 上)迁移到新合并的媒介上,从而腾出宝贵的内部存储空间。不同于因使用 MBR 而限制为 2TB 的传统存储设备,可合并的存储设备使用 GPT,因而文件存储限制约为 9ZB。

只有当开发者通过 android:installLocation 属性指示提供支持时,才能将应用放置在合并的存储媒介上。新安装的受支持的应用将自动放置在具有最多可用空间的存储设备上,用户可以在“设置”应用中在存储设备之间移动支持的应用。移动到已合并媒介的应用在媒介弹出时被记住,并在重新插入媒介时返回弹出前的状态。

安全性

平台为每个合并的设备随机生成加密密钥,该密钥存储在 Android 设备的内部存储设备上。这样可以有效地使得合并的媒介与内部存储设备一样安全。密钥与合并的设备(基于合并的分区 GUID)相关联。合并的设备使用通过 aes-cbc-essiv:sha256 算法和 128 位密钥大小配置的 dm-crypt 进行加密。

合并设备的磁盘布局紧密对应内部数据分区,包括 SELinux 标签等。当在 Android 设备上支持多用户时,合并的存储设备也通过与内部存储设备相同的隔离级别支持多用户。

由于合并的存储设备的内容与合并该设备的 Android 设备密切相关,加密密钥不应可以从父设备中进行提取,因此该存储设备无法装载到其他位置。

内容模式的默认加密算法是 aes-256-xts,而文件名的默认加密算法是 aes-256-heh。您可以通过分别更改属性 ro.crypto.volume.contents_modero.crypto.volume.filenames_mode 的值(更改方式为在 device.mk 中设置 PRODUCT_PROPERTY_OVERRIDES)来更改这些设置。

如果您的内核不支持 HEH 文件名加密,您可以通过将以下内容添加到 device.mk 来改用 CTS 模式:

PRODUCT_PROPERTY_OVERRIDES += \
ro.crypto.volume.filenames_mode=aes-256-cts

性能和稳定性

应该只考虑合并位于稳定位置(如电池盒内或防护盖后面的插槽)的外部存储媒介,以避免意外的数据丢失或损坏。尤其是,绝不应该考虑合并连接到手机或平板电脑的 USB 设备。一种常见的例外情况是连接到电视类设备的外部 U 盘,因为整个电视机通常安装在一个稳定的位置。

当用户合并新的存储设备时,平台将运行基准测试,并将其性能与内部存储设备进行比较。如果所合并设备的速度明显慢于内部存储设备,则平台将警告用户体验可能会受到影响。此基准根据常用 Android 应用的实际 I/O 行为得出。目前,AOSP 实现只会在超出单个阈值时警告用户,但是设备制造商可以进一步做出调整,例如如果存储卡运行非常缓慢,则完全拒绝合并。

合并的设备必须使用支持 POSIX 权限和扩展属性(如 ext4f2fs)的文件系统进行格式化。为了获得最佳性能,建议基于闪存的存储设备使用 f2fs 文件系统。

在执行周期性空闲维护时,平台将向合并的媒介发出 FI_TRIM(就像对待内部存储设备那样)。目前的 SD 卡规范不支持 DISCARD 命令;不过,内核会回退到使用 ERASE 命令,SD 卡固件可以选择使用该命令来实现优化目的。

修正双重加密

在 Android 8.x 及更低版本中,可合并的存储设备不支持 FBE。带有可合并的存储设备的所有现有设备都使用全盘加密 (FDE)。在 Android 9 中,可合并的存储设备支持 FBE,并使用元数据加密进行加密。但在默认情况下,文件内容已进行双重加密,因为可合并的存储设备具有 FDE 和 FBE 层。默认情况下,这两个层都会加密文件内容,这会降低设备性能。要解决双重加密问题并提高设备性能,请执行以下操作:

  1. 这些补丁程序添加到内核中。
  2. 要使用 vold 传达此项更改,请将以下内容添加到 device.mk 中:
    PRODUCT_PROPERTY_OVERRIDES += ro.crypto.allow_encrypt_override=true

如果您设置了此项内容,但内核修补程序不存在,则可合并的存储设备将无法工作,并且 vold 日志将包含一条错误消息(提示它无法创建 dm 设备)。

测试

要测试可合并的存储设备是否正常工作,请运行此 CTS 测试:

cts-tradefed run commandAndExit cts-dev \
    -m CtsAppSecurityHostTestCases \
    -t android.appsecurity.cts.AdoptableHostTest

要在设备没有内置插槽或正使用 USB 连接器实现有效的 adb 连接时验证 U 盘和 SD 卡的行为,请使用:

adb shell sm set-virtual-disk true