新的媒体控制中心、针对聊天消息的「对话泡」、包含智能家居控制中心和移动支付卡包的电源键菜单……尽管疫情打乱了几乎所有发布活动的节奏,不久前公布的 Android 11 测试版本还是为我们带来了不少新看点。

关联阅读:Android 11 的新功能确定就是它们了!

在我们能够直接感知到的视觉变化和功能改进之下,一些更加底层、但又与每位 Android 用户的最终体验息息相关的改动也不容小视,这当中最令开发者和用户关注的,莫过于曾在 Android 10 开发者预览版中短暂亮相、后来因为兼容性问题而不得不推迟的「沙盒」机制——即分区存储(scoped storage)特性了。

随着 Android 11 测试版在一加、小米、OPPO 等 OEM 机型中相继落地,分区存储特性距离我们其实也已经越来越近了。在这篇文章中,我们将对 Android 存储机制的原理、现状、存在的问题以及分区存储特性如何解决这些问题进行解释和说明。

你想要的「沙盒」究竟还有多远?Android 11 是非常关键的一个版本。

内置存储乱象从何而来

打开系统自带的文件浏览器,顺便再打开「显示隐藏文件」之类的开关——如果没有用存储空间隔离(以前也叫 存储重定向)进行过处理,存储空间中所包含的文件和文件夹就绝对不只有 标准文件目录

在这样的外部存储空间中找个文件好比大海捞针,但「看着很乱」并非当前 Android 存储机制带来的唯一问题。

在 A 应用被授予存储空间读写权限1的同时,这个应用也获得了读取存储空间中所有公共目录和公共文件的权限;恰好 B 应用获取到的设备标识符、用户画像等隐私数据并未按照规范进行存储,我们的隐私数据就这样成为了散落在存储空间中不受丝毫保护的、在「毒瘤应用」之间公开交换的廉价产品。

关联阅读:隐私保护更严格的 Android 10 之后,国产应用这样对你进行广告追踪

现阶段,一个应用能够读写的文件夹分为两种:一种是位于 ​sdcard/Android/data​ 的私有目录,其他第三方应用不能读写,对于一个应用来说属于内部目录;另一种是请求了文件权限之后的内置存储空间,也就是你打开文件管理器后看到的那个乱糟糟的界面,对于一个应用来说这属于外部目录。

在外部目录中应用如何创建文件夹、创建文件夹用来干嘛、可以创建多少文件与文件夹……现阶段 Android 系统并不能通过细致的读写权限进行强制干涉,授予了一个应用存储空间读写权限,几乎等同于给了它一张可以在外部存储空间中随意穿梭的通行证。因此也就有了上面提到的外部存储空间乱象。

所以 Android 系统的开放文件系统在为用户进行文件管理交互助力的同时,也在众多不规范应用的滥用之下成为了妨害用户实际体验和隐私数据的钥匙。

从这个角度来说,Google 什么时候强制推行「沙箱存储」特性其实都不算晚。

分区存储如何解决上述问题

分区存储是 Google 在 Android 10 中引入的新特性,在 Android 10 的测试过程中,由于用户遇到的兼容性问题和开发者社区的反馈,这个原本将在 Android 10 正式版中生效的机制最终推迟。

但 Google 不可能就此放弃分区存储,相反,Android 11 还进一步对这一机制进行了完善。根据 Google 的 设想,采用分区存储特性后的存储空间主要会带来这样几个变化:

  1. 系统能知道每个文件夹的来历,方便用户管理
  2. 卸载应用时能够一并移除应用相关文件夹
  3. 应用写入外部存储的文件对其他应用来说不可见
  4. 用户下载的文件对大多数应用不可见

为了实现这样的目标,Google 在 Android 11 中采用了下列方法来对存储空间的使用规范进行梳理:

写入不再随心所欲

相比以往应用申请外部存储读写权限就能随意读取、写入外部存储空间目录和文件的做法,以 Android 11 为目标平台进行开发和适配的应用所能够申请到的外部存储访问权限变更为只读权限

如需写入,应用还需要单独申请「所有文件访问权限」,该权限在 Play 应用商店后续的指南和 规范 中进一步被明确为面向文件管理器、文件备份工具等特殊应用才能申请的权限。

这一改动从根源上断绝了应用随意读取外部存储空间目录、文件甚至其他应用文件的可能性。

一个应用一个「沙箱」

在上述前提下,应用在外部存储空间中能够写入的文件自然也从我们在本文第一部分中提到的公开的、宛如「自由贸易市场」的外部目录变成了应用专属的外部目录(app-specific files)。

专属,意味着这个目录对除了这个应用本身以外的其他应用而言是绝对不可见的,这也就是我们俗称的隔离或应用「沙盒」

以大家所熟知的「全家桶」应用 A 和应用 B 为例,在以往的外部存储空间机制作用下,应用 A 可以直接向外部存储空间写入 5 个垃圾文件夹并在其中一个文件夹里放上我们的隐私数据,拥有同样访问权限的应用 B 不仅可以参考应用 A 的做法创建 15 个垃圾文件,同时还能顺便读取一下应用 A 获取到的隐私数据。

分区存储机制双向切断了这种读写路径,在分区存储机制下,应用 A 和应用 B 只能把捡来的垃圾和死缠烂打要来的小秘密放在各自的小盒子里;同时小盒子和小盒子之间也不互通,应用 A 和应用 B 不再拥有交互数据的机会。

因此对这类应用而言,如何将自己包装成为「文件管理工具」并骗过 Google Play 的审核机制也许才是今后的唯一出路了。

借规范接口良性互通

不过这样一来又会产生新的问题:

微信要怎么发送浏览器下载的图片呢?2

对于这些需要在应用间共享的多媒体(图片、音频、视频)和文档(如 PDF、电子书等等)文件,Google 提供了一个 API 来方便应用将多媒体和文档文件存储至标准的公用目录,如根目录下的 ​/Pictures​。如果要读取多媒体文件,在用户授予了存储权限后,应用可以通过 MediaStore​ 这个 API 来读取这些标准公用目录中的文件。

如果需要读写非多媒体类的其他下载文件,则需要通过支持 存储访问框架(Storage Access Framework)的文件选取器进行,所以在分区存储机制下如果微信想要发送文件给其他人,还必须舍弃掉当前自己采用的那套并不规范的文件选取器。

采用标准 SAF 框架的文件选取器(左)和微信「自主研发」的文件选取器

最后,针对诸如 Solid Explorer 这种第三方文件管理器和钛备份、Swift Backup 这类备份工具,就像我们上面所提到的那样,Google 引入一个特殊的权限​来赋予其读写所有共享存储空间文件(包括非多媒体文件)的权限,但这个权限的作用范围依然不包括应用专属目录(内部和外部目录)。

注:Swift Backup 开发者已经通过 Google 官方提供的途径提交了适配 Android 11 和分区存储特性的新版本。

总体来说,分区存储机制下,应用对于外置存储的读写将被隔离至独立的沙盒文件夹中而非真正的根目录,以此避免了污染存储空间的问题;需要在多个应用间传递的文件数据的行为也将更多地借助规范 API 和系统组件来进行。

对 Android 平台而言,直接读写原始文件的「蛮荒时代」即将过去。

第三方应用何时适配

众所周知,一些开发者擅长利用「拖字诀」逃避 Google 的规范要求,好在 Google 也意识到了这一点。近年来 Google 对 Play 商店上架的应用提出了一个又一个看似严格的强制要求,无形之中推动着 Android 应用生态一点点向好。此前强制要求 64 位架构分发就是个例子,这个规定直接促成了微信这类「优秀产品」针对 64 位架构设备进行了适配。

针对分区存储,Google 考虑到兼容问题为应用开发者留出了充足的时间来进行适配工作,但同时也规定了「应用的 SDK 不能比当前主要 Android 版本低一个版本以上」,这个有点绕的规定用更直白的方式来解释即是 2021 年上架 Play 商店应用的 SDK 版本不能低于 Android 11(SDK 30)

大家不妨这样理解:如果某个应用想要用上新的功能和接口,适配的 API 和系统版本肯定要跟上;而每个 SDK 对应了一个系统版本,比如 SDK 30 对应的就是 Android 11。因此上面的规定自然就可以理解为,2021 年年底之前,至少所有在 Google Play 上架的应用都必须适配即将于今年第三季度推出正式版本的 Android 11。

大家翘首以盼的分区存储特性,届时自然也会作为一项默认规范全面铺开。

而就目前来说,已知适配了分区存储特性的国产应用不多,QQ 在不久前调整了下载文件的存储机制,但总体而言文件结构依然不符合规范;百度系 App 此前也公布过类似的 适配计划,目前未见实装。对国内应用而言适配「沙箱」特性所剩下的时间并不算多。

更重要的是,在我们已经谈论了近 20 年「全球化」话题的今天,部分国产应用依然可以依靠不在海外运营、规避 Play 商店上架、提供第三方下载和安装方式等方法来避过这一机制,Android 的存储空间能否真正迎来天朗气清,其实还需要屏幕前的你、我,国内手机厂商和应用开发者的共同督促。

参考链接:

关联阅读:

> 下载少数派 客户端、关注 少数派公众号,读懂 Android 系统的每个细节 🤔