Scoped storage

Scoped storage limits app access to external storage. In Android 11 or higher, apps targeting API 30 or higher must use scoped storage. Previously in Android 10, apps could opt out of scoped storage.

App access restrictions

The goal of scoped storage is to protect the privacy of app and user data. This includes protecting user information (such as photo metadata), preventing apps from modifying or deleting user files without explicit permission, and protecting sensitive user documents downloaded to Download or other folders.

Apps using scoped storage can have the following levels of access (actual access is implementation specific).

  • Read and write access to their own files with no permissions
  • Read access to other apps' media files with READ_EXTERNAL_STORAGE permission
  • Write access to other apps' media files is allowed only with direct user consent (exceptions granted to System Gallery and apps that are eligible for All Files access)
  • No read or write access to other apps' external app data directories

Use scoped storage with FUSE

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

Android 10 对 MediaProvider 的文件访问强制执行了分区存储规则,但由于拦截内核调用需要付出很大努力,因此未对直接文件路径访问(例如,使用 File API 和 NDK API)执行此规则。因此,分区存储中的应用无法使用直接文件路径访问文件。这种限制影响了应用开发者进行适配的能力,因为它需要进行大量的代码更改,才能将 File API 访问重写为 MediaProvider API。

FUSE 和 SDCardFS

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

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

FUSE 性能调优

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

FUSE 调优包括以下调整

  • 绕过 FUSE 以提高对 Android/dataAndroid/obb 目录的性能,从而改进依赖于这些目录的游戏应用的性能。
  • 优化(例如,调整 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 个文件的目录,或者在文件系统上创建或删除包含 100 万个文件的目录。批量文件操作可能会受到 Android 11 上 FUSE 的影响,但如果此类应用符合 MANAGE_EXTERNAL_STORAGE 权限的条件,它们将受益于 2020 年 10 月更新中包含的性能优化。

为了避免 FUSE 性能开销,应用可以将数据存储在外部私有存储设备中,或使用 ContentProvider 类中的批量 API 来绕过 FUSE 并获得性能优化的路径。此外,MediaProvider 系统组件的 2020 年 10 月更新包括针对持有 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 性能衰退和错误。