最近,我发现,如果我从中/sdcard/Download
删除文件,则会从中删除文件/storage/emulated/0/Download
。如果我将文件添加到/sdcard/Download
其中,则会在中复制它们/storage/emulated/0/Download
。
那是什么/storage/emulated/0/
?为了什么目的,我们在Android文件系统中拥有它?
最近,我发现,如果我从中/sdcard/Download
删除文件,则会从中删除文件/storage/emulated/0/Download
。如果我将文件添加到/sdcard/Download
其中,则会在中复制它们/storage/emulated/0/Download
。
那是什么/storage/emulated/0/
?为了什么目的,我们在Android文件系统中拥有它?
Answers:
/storage/emulated/0/Download
是文件的实际路径。
/sdcard/Download
是到实际路径的符号链接 /storage/emulated/0/Download
但是,实际文件位于中的文件系统中/data/media
,然后将其挂载到/storage/emulated/0
(通常也挂载到其他挂载点)
甲符号连接在计算中,一个符号链接是包含在绝对或相对路径的形式的另一文件或目录的引用,并影响路径名解析任何文件的术语。到1978年,DEC和Data General的RDOS的微型计算机操作系统中已经存在符号链接。
/storage/emulated/0/
实际上是/data/media/0/
通过模拟/虚拟文件系统公开的,而不是实际的。
这是参考我以前的答案在这里,但更多的相关细节。
/sdcard >S> /storage/emulated/legacy >S> /mnt/shell/emulated/0
/mnt/shell/emulated >E> /data/media
# for (Java) Android apps (running inside zygote virtual machine)
# "/storage to VIEW" bind mount is inside a separate mount namespace for every app
/sdcard >S> /storage/self/primary
/storage/self >B> /mnt/user/USER-ID
/mnt/user/USER-ID/primary >S> /storage/emulated/USER-ID
/storage/emulated >B> /mnt/runtime/VIEW/emulated
/mnt/runtime/VIEW/emulated >E> /data/media
# for services/daemons/processes in root/global namespace (VIEW = default)
/sdcard >S> /storage/self/primary
/storage >B> /mnt/runtime/default
/mnt/runtime/default/self/primary >S> /mnt/user/USER-ID/primary
/mnt/user/USER-ID/primary >S> /storage/emulated/USER-ID
/storage/emulated >B> /mnt/runtime/default/emulated
/mnt/runtime/default/emulated >E> /data/media
* >S>
用于符号链接,>E>
用于仿真和>B>
用于绑定安装
* USER-ID
当前用户(如果是Multiple Users
或)Work Profile
,通常0
是设备所有者的
* VIEW
是read
(对于具有许可权的应用程序。READ_EXTERNAL_STORAGE)或write
(permission.WRITE_EXTERNAL_STORAGE)或default
(对于在root中运行的进程之一/ global mount名称空间,即在zygote之外)
*与先前的Android版本略有不同,但是自实施以来,仿真的概念是相同的。
*有关Android的mount名称空间实现的更多详细信息,请参见此答案。
简而言之,/sdcard
并且/storage/emulated/0
-代表FAT / vFAT / FAT32文件系统- 通过或仿真指向/data/media/0
(或/mnt/expand/[UUID]/media/0
在采用存储的情况下)。 FUSE
sdcardfs
符号链接和绑定安装(请参阅“创建绑定安装”)不是特定于Android的,而是通常与Linux相关的,因此不在此问题的范围内,因为该问题主要是关于仿真部分的。
为什么要在这里进行仿真?仿真文件系统是实际文件系统(ext4
或f2fs
)上的抽象层,主要用于两个目的:
阅读Android的存储之旅以了解详细信息,摘要为:
早期的Android设备内部存储空间不足,并且(物理上)依赖外部SD卡,这些SD卡传统上使用FAT系列文件系统来确保与大多数PC的兼容性(请参阅Microsoft在PC世界中的主导地位)。
当内部存储的容量增加时,相同的文件系统将移至内部(仍称为“外部”)SD卡。
但是FAT / vFAT实施存在两个主要问题,Google逐渐解决了这些问题:
ioctls
像FS_IOC_FIEMAP
)。因此,SD卡上的所有数据对所有应用程序都是可用的(因为每个Android应用程序都是UNIX / Linux用户且具有uid),没有任何限制,因此引发了严重的隐私和安全问题。通过仿真解决了这两个问题:
/data
拥有ext4
文件系统的分区(或以前在某些设备上的独立/ sdcard分区)(逐渐由取代f2fs
),完全实现了UNIX权限。 /data
分区不能再暴露给PC有两个原因:(1)
它包含许多设置和应用程序数据,这些数据将受到保护,免受其他应用程序和人类用户的攻击。(2)
Windows不支持Linux文件系统。android.process.media
)上在Android上运行,而该应用程序()已在Android框架中完全沙箱化,无法执行任何升级任务。现在,这些应用程序(以及MTP,也是一个应用程序)与模拟存储进行交互,而不是与/data/media
,同时实现了这两个目的,即在下面强制执行权限检查,并看起来像FAT文件系统在上表面。
Google现在通过sdcardfs实现仿真,以克服FUSE的缺点;输入/输出开销(即提高读取/写入速度)是一个主要问题。
外部存储
权限:可以使用以下示例演示外部存储上公共和私有文件的
概念:安装Termux应用程序。
创建目录和。
创建文件和。
执行以下命令:/sdcard/Android/data/com.termux/test_dir
/sdcard/test_dir
/sdcard/Android/data/com.termux/test_file
/sdcard/Android/data/com.termux/test_file
*您应该已安装WhatsApp或选择其他一些应用程序的专用文件夹。
现在,强制停止Termux应用程序并授予存储权限。再次执行命令:
查看相同文件和目录的权限差异。当有数百个应用程序(用户)要同时处理时,如果没有在本地Linux文件系统上进行仿真,这似乎不可能简单地实现。这是文件系统仿真,它使同一文件可以同时以三组不同的权限公开,而与实际文件系统上的原始权限无关:
# touch /data/media/0/test_file
# stat -c '%a %u %g %n' /data/media/0/test_file
644 1023 1023 /data/media/0/test_file
# stat -c '%a %u %g %n' /mnt/runtime/*/emulated/0/test_file
660 0 1015 /mnt/runtime/default/emulated/0/test_file
640 0 9997 /mnt/runtime/read/emulated/0/test_file
660 0 9997 /mnt/runtime/write/emulated/0/test_file
有关:
FAT-like permission-less filesystem
Android早期版本,以确保向后兼容,并且符合Android外部存储概念的设计。我进行了修改以阐明我的观点。