参考: http://www.cnblogs.com/wetest/p/8536868.html
Android存储系统架构篇: http://gityuan.com/2016/07/23/android-io-arch/
引子:
-
通过打印Android文件在内核ext4层和上层的全路径,会发现同样的文件绝对路径竟然不一样,例如:在libc层绝对路径为/storage/…,但在内核ext4层打印的为/media/… .。这里牵扯到Android对外存的管理方面的东西。
-
APP上层读写的文件进程id(getpid()),在内核中访问外存时变成了叫/system/bin/sdcard的守护进程。百思不得解。
-
一个简简单单外部存储,会存在这么多奇奇怪怪的路径: /sdcard 、 /mnt/sdcard 、 /storage/extSdCard 、 /mnt/shell/emulated/0 、 /storage/emulated/0 、 /mnt/shell/runtime/default/emulated/0 … 其实这背后代表了一项项技术的成熟与发布:模拟外部存储、多用户、运行时权限…
1. 各版本外部存储特性
- Android 4.0
- 支持模拟外部存储(通过FUSE实现)
- 出现了主外部存储,以及二级外部存储(没有接口对外暴露)
- 支持MTP(Media Transfer Protocol), PTP协议(Picture Transfer Protocol)
- Android 4.1
- 开发者选项出现“强制应用读权限才可以进行读操作”的开关
- Android 4.2
- 支持多用户,每个用户拥有独立的外部存储
- Android 4.4
- 读操作需要声明READ_EXTERNAL_STORAGE权限
- 应用读写在外部存储的应用目录(/sdcard/Android/< pkg >/)不需要声明权限。
- 增加了Contest.getExternalFileDirs()接口,可以获取应用在主外部存储和其他二级外部存储下的files路径
- 引入存储访问框架(SAF , Storage Access Framework)
- Android 6.0
- 外部存储支持动态权限管理
- Adoptable Storage特性
- Android 7.0
- 引入作用域目录访问
补充一个点:
如果应用的minSdkVersion和targetSdkVersion设置成<=3,系统会默认授予READ_EXTERNAL_STORAGE权限。
额 好吧,这里有的我也不懂。
不过现在的FUSE已经被sdcardFS代替了。
sdcardFS简要介绍
- sdcardfs:android中用于控制文件访问的权限。对内置SD卡的系统调用,先经过sdcardfs,然后把访问路径改为ext4文件系统的真正路径,再到达ext4文件系统。ext4执行完以后,把结果返回给sdcardfs,再返回给调用者。
- Android将APP数据放置于:用户数据空间data目录和用户sdcard目录。其在物理上是同属一个分区。这个分区也采用同一个文件系统—ext4文件系统。为了控制文件访问的权限,用户sdcard目录用sdcardfs管理来进行其访问权限控制。
- 所以,一个APP的数据对文件的访问关系如图 24所示:
2. 部分特性讲解
1. 模拟外部存储
a. 必要性
- FAT32属于微软专利,可能存在许可和法律问题(相关文章);
- 可以定制Android自己的外部存储访问规则;
- 为多用户做铺垫;
b.实现原理
系统/system/bin/sdcard守护进程,使用FUSE(现在已经被sdcardFS替代)实现类FAT格式SD卡文件系统的模拟,也就是我们经常说的内置SD卡。
- 用户空间文件系统(Filesystem in Userspace,简称FUSE)是一个面向类Unix计算机操作系统的软件接口,它使无特权的用户能够无需编辑内核代码而创建自己的文件系统。目前Linux通过内核模式对此进行支持。
sdcard守护进程模拟外部存储大致流程(Android 4.0为例):
- 首先,指定/data/media目录用于模拟外部存储。该路径的owner和group一般为media_rw, 这样保证只有sdcard程序或root进程能够访问该目录。
进过打印查看,/system/bin/sdcard 守护进程的 进程名 为: sdcard
- sdcard守护进程启动后,打开/dev/fuse设备。
- 在/mnt/sdcard目录挂载fuse文件系统。
- 开线程,在线程中处理文件系统事件,并将结果写回。
经过上面一系列步骤,sdcard进程在/mnt/sdcard路径上创建了一个FUSE文件系统,所有对/mnt/sdcard将转为事件由sdcard守护进程处理,并对应到/sdcard/media目录。
例如, 应用创建/mnt/sdcard/a文件,实际是创建/data/media/a文件。
c.优点
- 模拟外部存储容量和/data分区是共享的,用户数据在内外存储的分配更加自由;
- 模拟外部存储本身不可卸载,不会因为卸载导致应用访问出现问题,也减少了外部因素导致被破坏的情况;
- 所有的访问都经过sdcard守护进程,Android可以定制访问规则;
d.劣势
- 性能上存在一定损失
e. 影响
- Android 6.0以后,由于动态权限管理的需要,会存在多个fuse挂载点,这导致inotify/FileObserver对外部存储进行文件事件监控时,会丢失事件。
inotify是Linux核心子系统之一,作为文件系统的附加功能,他可监控文件系统并将异动通知应用程序。 – 维基百科(https://zh.wikipedia.org/wiki/Inotify)
2. 多用户
a.支持版本
- Android 4.2开始支持多用户,但仅限平板;
- Android 5.0开始,设备制造商可以在编译时候开启多用户模块;
接下来http://www.cnblogs.com/wetest/p/8536868.html 这个博客对源码进行了分析,洞察事物本质,值得仔细看一看!!!!