范围存储

范围存储限制应用程序对外部存储的访问。在 Android 11 或更高版本中,面向 API 30 或更高版本的应用必须使用范围存储。在之前的 Android 10 中,应用可以选择退出范围存储。

应用访问限制

范围存储的目标是保护应用程序和用户数据的隐私。这包括保护用户信息(例如照片元数据),防止应用在未经明确许可的情况下修改或删除用户文件,以及保护下载到下载或其他文件夹的敏感用户文档。

使用范围存储的应用程序可以具有以下访问级别(实际访问权限是特定于实现的)。

  • 在没有权限的情况下对自己的文件进行读写访问
  • 具有READ_EXTERNAL_STORAGE权限的其他应用程序媒体文件的READ_EXTERNAL_STORAGE权限
  • 只有在用户直接同意的情况下才允许对其他应用程序的媒体文件进行写入访问(授予系统库和有资格获得所有文件访问权限的应用程序除外)
  • 没有对其他应用程序的外部应用程序数据目录的读取写入权限

将范围存储与 FUSE 结合使用

Android 11 或更高版本支持用户空间中的文件系统 (FUSE),这使 MediaProvider 模块能够检查用户空间中的文件操作,并根据允许拒绝编辑访问的策略来控制对文件的访问。范围存储中使用 FUSE 的应用程序获得范围存储的隐私功能以及使用直接文件路径访问文件的能力(保持文件 API 在应用程序中工作)。

由于拦截内核调用需要付出努力,Android 10 对 MediaProvider 的文件访问强制实施了范围存储规则,但不适用于直接文件路径访问(例如,使用 File API 和 NDK API)。因此,范围存储中的应用程序无法使用直接文件路径访问文件。此限制影响了应用程序开发人员的适应能力,因为它需要大量代码更改来重写 File API 对 MediaProvider API 的访问。

FUSE 和 SDCardFS

Android 11 对 FUSE 的支持与SDCardFS 的弃用无关,但确实为以前使用 SDCardFS 的设备提供了媒体存储的替代方案。设备:

  • 使用内核 5.4 或更高版本启动 Android 11 或更高版本无法使用 SDCardFS。
  • 升级到 Android 11 或更高版本可以在 SDCardFS 之上托管 FUSE 以拦截文件操作并满足隐私目标。

FUSE 性能调优

Android 之前在 Android 7 或更低版本中支持 FUSE,其中外部存储被挂载为 FUSE。由于该 FUSE 实现的性能和死锁问题,Android 8 引入了 SDCardFS。 Android 11 使用改进的、经过更好测试的libfuse实现重新引入了对 FUSE 的支持,可以对其进行调整以解决 Android 7 或更低版本中的性能问题。

FUSE 调整包括以下调整:

  • 绕过Android/dataAndroid/obb目录的 FUSE,以提高依赖这些目录的游戏应用程序的性能。
  • 优化(例如调整 FUSE 文件系统的预读和脏比)以保持读取性能和媒体播放流畅。
  • 使用 FUSE 回写缓存。
  • 缓存权限以减少对系统服务器的 IPC。
  • 对具有所有文件访问权限的应用程序进行了优化,以加快批量操作。

上述调整可以在 FUSE 和非 FUSE 设备之间产生相当的性能。例如,测试使用 FUSE 的 Pixel 2 和使用 Media Store 的 Pixel 2 发现文件路径访问和 Media Store 之间的顺序读取性能(例如,视频播放)相当。但是,使用 FUSE 的顺序写入稍微差一些,随机读取和写入的速度可能会慢两倍。

性能测量可以在不同设备之间以及在特定用例之间发生变化。因为 MediaProvider API 提供最一致的性能,所以关心性能的应用程序开发人员应该在他们的应用程序中使用 MediaProvider API。

减轻 FUSE 性能影响

FUSE 性能影响仅限于存储在外部共享存储上的文件的重度用户。外部私有存储(包括android/dataandroid/obb目录)被 FUSE 绕过,而内部存储(例如/data/data ,许多应用程序存储数据以保持其加密和安全)没有安装 FUSE。

  • 共享外部存储的轻量级用户应用程序通常与一组有限的文件(通常少于 100 个文件)进行交互。这些应用受益于对常见读写操作的现有优化,并且在 Android 11 中不会看到任何与 FUSE 相关的性能影响。

  • 大量使用共享外部存储的应用程序通常会执行批量文件操作,例如列出或删除包含 1000 个文件的目录,或者在文件系统上创建或删除包含一百万个文件的目录。批量文件操作可能会受到 Android 11 上 FUSE 的影响,但如果此类应用符合MANAGE_EXTERNAL_STORAGE权限的条件,它们将受益于 2020 年 10 月更新中包含的性​​能优化。

为了避免 FUSE 性能开销,应用程序可以将数据存储在外部私有存储中或使用ContentProvider类中的批量 API 绕过 FUSE 并获得性能优化的路径。此外,2020 年 10 月对 MediaProvider 系统组件的更新包括对拥有MANAGE_EXTERNAL_STORAGE权限的文件管理器和类似应用程序(例如备份/恢复、防病毒)的性能优化。

隐私高于性能

在针对 FUSE 进行了调整的设备上,大多数关键用户旅程在 Android 10 和 Android 11 之间的性能相同。但是,在针对一组文件操作测试基准时,Android 11 的性能可能比 Android 10 差。对于执行的文件访问模式在 Android 11 中更糟糕的是(例如,随机读取或写入),我们建议使用 MediaProvider API 为应用程序提供非 FUSE 访问模式,这是最佳且始终如一的性能选项。

MediaProvider 和 FUSE 更新

MediaProvider系统组件的行为因 Android 版本而异。

  • 在 Android 10 及更低版本中,SDCardFS 是文件系统,MediaProvider 为文件集合(例如,图像、视频、音乐文件等)提供了一个接口。当应用程序使用 File API 创建文件时,它可以要求 MediaProvider 扫描文件并将其记录在数据库中。

  • 在 Android 11 或更高版本中, SDCardFS已被弃用,MediaProvider 成为外部存储的文件系统处理程序(用于 FUSE),使外部存储上的文件系统和 MediaProvider 数据库保持一致。作为 FUSE 文件系统的用户空间处理程序,MediaProvider 可以拦截内核调用并确保文件操作是隐私安全的。

在 Android 11 及更高版本中,MediaProvider 也是一个模块化系统组件(一个 Mainline 模块),可以在 Android 版本之外进行更新。这意味着在 MediaProvider 中发现的性能、隐私或安全问题可以通过 Google Play 商店或其他合作伙伴提供的机制进行修复和传输。 FUSE 处理程序预期范围内的任何内容也是可更新的,支持更新以修复 FUSE 性能回归和错误。