
1. 先搞清楚你看不见的文件不存在可能只是个幻觉最近连续接到好几个类似的求助症状几乎一模一样某个App里明明显示下载完成了图片/文档也预览不了下载的文件在系统文件管理器里又找不到有人用adb shell想进到/storage/emulated/0/Android/data/目录下面去处理文件结果一个chmod直接被怼回来一句Operation not permitted。很多人第一反应就是Ext4文件系统坏了要格式化要刷机。我可以直接告诉你大部分情况真不是文件系统的锅。Android的存储体系从内核到应用层隔了好几层Ext4只是最底层的物理文件存放者文件在不在磁盘上是文件系统的事而文件让不让你看见、让不让你改是上面几层权限机制的事。你看到文件丢了权限被拒绝这些表面症状很多时候根子不在Ext4而在VFS层的权限过滤、SELinux策略、甚至Android 11之后的分区存储设计上。这篇文章我就从一次完整的排查经历讲起把Android设备上文件系统问题最常见的几类场景、背后的原理、以及需要用到的工具链和命令全部捋一遍。适合遇到同样问题的普通用户也适合做Android系统开发、应用开发、以及搞嵌入式Linux的朋友参考至少能让你下次再碰到类似现象时知道先查哪里、再查哪里而不是一上来就走进格式化这条不归路。2. 文件系统问题排查的第一步先从最底层看分区和挂载做问题排查我习惯先确定一件事我面对的文件物理上到底落在哪块磁盘分区上很多人在Android上把/sdcard、/storage/emulated/0/、/data当成同一个东西这其实是大错特错。在开始怀疑Ext4之前第一步永远是把视距拉高把整台设备的分区布局看清楚。2.1 Android设备的Ext4分区到底有哪几个现在的Android手机物理分区大体上分成这么几类boot分区存放内核和ramdisk通常不是ext4而是raw格式system分区系统只读文件Android 10之后很多设备用system-as-root挂在根目录/下ext4或erofs格式带dm-verity校验不能随便写入vendor分区厂商定制内容同样只读校验data分区用户数据、应用数据、配置文件全在这一般就是一块ext4部分中高端机型会改用f2fs挂载在/data上cache分区老设备上独立存在新设备已经合并进data或metadata了metadata分区存储加密元数据、rollback保护等。真正和我们日常文件不见了文件打不开强相关的几乎都是/data这一块ext4分区。而大家非常熟悉的/storage/emulated/0/并不是一个独立分区它是一个FUSE用户态文件系统本尊指向/data/media/0/。这句话请先刻在脑子里后面很多混淆都源于此。2.2 用mount和df把挂载关系看透彻连接设备后第一步用这三条命令把底裤扒干净adb shell # 查看所有挂载点重点看根分区和data分区 cat /proc/mounts | grep -E /data | / # 查看文件系统类型和容量 df -T /data /storage/emulated/0 # 用stat确认某个目录底层文件系统的详细信息 stat -f /data /storage/emulated/0/Android/data举个例子查看输出会看到类似这样的行/dev/block/sda17 /data ext4 rw,seclabel,relatime,dataordered 0 0 tmpfs /storage/emulated/0 fuse rw,nosuid,nodev,noexec,noatime,user_id0,group_id9999 0 0注意这里的信息量很大。/data是真正的ext4挂载/storage/emulated/0的挂载点写的是/storage/emulated/0类型为fuse说明所有对手机内部存储的文件操作都会先经过FUSE这层用户态代理再由它去读写底层的/data/media。如果FUSE这一层出了问题——比如守护进程崩溃、权限校验卡住——表现就是文件管理器打不开目录或者App下载的文件找不到但底层ext4完全健康。2.3 挂载参数里隐藏的信息不要忽略继续细读/proc/mounts里/data那行的挂载参数每个词都有讲究rw/ro可读写还是只读。如果变成ro十有八九是ext4的journal出错了系统自动remount成只读保护数据这是个大信号contextu:object_r:开头的seclabel相关信息代表SELinux已经接管这块分区dataorderedext4的日志模式默认是ordered写数据先落盘、再记录元数据日志inline_data允许小文件内容直接塞进inode里减少磁盘寻道但断电时这种文件恢复逻辑更特殊discard允许后台TRIM对闪存寿命有好处但掉电场景下也会造成一些数据块提前被标记为可回收。还有一个经常查不到但值得确认的信息实际ext4特性。用tune2fs看# 先找到userdata分区的块设备路径 ls -l /dev/block/by-name/ tune2fs -l /dev/block/by-name/userdata输出里的Filesystem features一栏会列出filetype, ext_attr, extent, flex_bg, inline_data, metadata_csum这些特性。如果设备用了metadata_csum元数据校验和那e2fsck的版本就不能太老低版本的工具可能会误判。这也是很多人把分区弄得更坏的原因之一用了老电脑上的旧版e2fsck去修新内核格式化出来的ext4修完以后问题更严重了。3. 文件能看见就是打不开DAC权限与SELinux的双重过滤有一次排查一个第三方App崩溃问题log里反复出现Permission denied。用adb shell进去看文件ls -l /data/data/xxx/看到文件明明在那owner也对权限位也没问题可App就是打不开。很多人到这里就懵了开始怀疑文件系统坏了。其实不是Ext4的问题而是遗漏了第二道检查SELinux上下文。3.1 ls -lZ比ls -l多出来的信息才是关键在Android的/data分区上传统的Linux权限位DAC只是第一道闸门SELinuxMAC是第二道。文件能不能被访问要两次检查都通过才行。# 同时查看权限位和SELinux上下文 ls -lZ /data/data/com.some.app/输出类似drwxrwx--x 2 u0_a123 u0_a123 u:object_r:app_data_file:s0:c512,c768 4096 2024-01-01 10:30 databases drwxrwx--x 2 u0_a123 u0_a123 u:object_r:app_data_file:s0:c512,c768 4096 2024-01-01 10:32 files注意SELinux标签里的c512,c768这是基于category的隔离两个不同的App即便UID相同SELinux也会通过category把它们的数据隔开。如果某个目录的SELinux标签变成了u:object_r:unlabeled:s0那问题就大了App自己的访问会被SELinux拦下报错表现就是五花八门的Permission denied哪怕root去看文件都在。我遇到过一次真实的场景某个App升级之后突然崩溃查了半天发现是OTA流程里对/data/media的relabel没跑完整导致目录继承了错误的SELinux上下文。修复命令倒是简单# 需要root su 0 restorecon -R /data/media/0/Android/data/包名但难点在于你能想到去查SELinux上下文——这正是很多人排查时的盲区。所以记住这个顺序文件打不开先ls -lZ同时看DAC和SELinux别只看传统的ls -l。3.2 adb shell权限的天花板还有一类很常见的场景是开发者自己用adb shell去操作App的私有目录adb shell cd /data/data/com.some.app/files ls # 能看到 echo hello test.txt # 报错Permission denied这里有两层原因。第一层adb shell跑在shell这个UID下虽然用户组里带sdcard_rw对/storage/emulated/0有权限但对/data/data下App私有目录没有DAC权限因为那些目录owner是App自己的UID。第二层就算你su切到root了在Android的SELinux策略里shell domain和su domain访问app_data_file类型也有一堆限制除非临时把SELinux调成宽容模式# 已root设备的典型操作 su 0 setenforce 0但这不是普通用户该干的事而且每次重启SELinux都会自动回到强制模式。真正结论是不要指望靠adb shell去翻App的私有目录这是系统隔离设计的一部分和文件系统损坏没半点关系。3.3 那chmod为什么也会被拒绝回到开头那个热搜词——unable to chmod /storage/emulated/0/android/data/xxx: operation not permitted。这个现象在Android 11设备上尤其常见哪怕你把目标目录的owner都改成自己了chmod依然可能失败。原因在于/storage/emulated/0这层是FUSE挂载内核里对FUSE的权限模型做了裁剪它根本不允许上层用户修改ownership和文件mode位。不是说你权限不够而是这层文件系统在设计和实现上就不支持这些操作。传统Linux经验里我是owner我就能chmod的惯性思维在这里完全不适用。这也就解释了为什么很多用户拿着已经root的MT管理器还是改不了/storage/emulated/0/Android/data下的文件属性——root只是给了你一个通行证但FUSE层的规则是另一套逻辑。遇到这种场景正路是用adb shell配合FUSE的user_id/group_id协商机制去操作或者直接走/data/media/0/Android/data/...这个底层真实路径root权限下绕开FUSE层再去改文件属性。4. Android/data越权访问之争分区存储设计带来的文件管理混乱最近的热词里有一大串特别扎眼/storage/emulated/0/android/data/com.tencent.tmgp.sgame/files/pandora/pr、content://com.baidu.searchbox.fileprovider/baiddpath/android/data/...、app里既打不开预览下载的文件系统又找不到。这些词说明什么说明大量用户正在被同一个问题折磨App把文件下载到了自己的Android/data目录下用户在文件管理器里却找不到或者找到了也打不开。4.1 分区存储不是bug