从Android6.0开始,Android支持移动存储(adoptable storage),例如SD卡或者USB。移动存储可以像内部存储一样加密和格式化,可以存储所有类型的应用数据。
## 权限
是否访问外部存储由各种Android权限保护。
* 从Android1.0开始,写访问需要 WRITE_EXTERNAL_STORAGE 权限;
* 从Android4.0开始,读访问需要READ_EXTERNAL_STORAGE。
* 从Android4.4开始,外部存储设备上的文件,也能够基于目录结构来合成(synthesized )不同的DAC权限(owner,group,mode)。这容许应用能够在外部存储上管理一个包相关的目录,而无需WRITE_EXTERNAL_STORAGE 。例如, 应用com.example.foo 可以自由访问外部存储上的Android/data/com.example.foo/。这种合成权限是通过fuse守护来包裹原始存储设备来完成的。
## 运行时权限
Android6.0 引入了新的运行时权限(runtime permissions)模型,用于应用在运行中必要时申请权限。由于新模型包含了READ/WRITE_EXTERNAL_STORAGE,因此平台需要在不杀死或者重启运行中的应用的前提下,动态对存储访问授权。这是通过维护所有挂载的存储设备的三个不同视图来实现的:
* /mnt/runtime/default 对所有的应用、root名字空间(adb 和其他系统组件)可见,而无需任何权限
* /mnt/runtime/read 对有READ_EXTERNAL_STORAGE权限的应用可见。
* /mnt/runtime/write 对有WRITE_EXTERNAL_STORAGE权限的应用可见。
在zygote fork时,我们为每个运行中的应用创建一个mount名字空间,在其中bind mount合适的初始视图。然后,当被授予运行时权限时,vold在运行中的应用的名字空间上,通过bind mount来更新视图。注意,如果权限被撤销,将意味着该应用被kill。
系统使用**setns()**函数来实现上述特性,这要求Linux3.8,不过Linux3.4加上补丁上也可以支持该功能。
在Android6.0中,第三方应用不再被加入sdcard_r和sdcard_rw组中。相反,通过给应用挂载合适的**运行时视图**,实现对外部存储的访问控制。同时,使用everybodyGID来进行的跨用户交互被禁止了。