11、文件系统与权限:adb shell 下的文件操作与 Android 文件系统结构
说实话,很多初学者觉得 ADB 就是装个应用、截个图。但真正让我觉得「嗯,这工具开始有灵魂了」的时刻,是在我学会用 adb shell 操作文件系统之后。
你想想看,手机在你手里,你只能看到「相册」「文件管理」这些 App 给你展示的东西。但通过 adb shell,你能直接钻进系统底层,看到真正的目录结构。这种感觉,就像你第一次拿到后台数据库的 root 权限一样——爽,但也危险。
我个人习惯,在调试任何 Android 设备前,都会先跑一遍 adb shell ls -l /,看看根目录下都有什么。这能帮我快速判断设备的系统版本、分区情况,甚至能发现一些被隐藏的异常文件。
11.1 Android 文件系统结构:你得知道东西都放在哪
Android 基于 Linux 内核,所以文件系统也是类 Unix 的树形结构。但有几个目录,你必须要记住,因为日常调试几乎天天跟它们打交道。
| 目录 | 用途 | 权限特点 | 我踩过的坑 |
|---|---|---|---|
/data |
用户数据区:应用安装包、数据库、SharedPreferences、缓存 | 普通应用不可读,root 或 shell 用户可读写 | 有一次我手快删了 /data/data/com.android.providers.contacts,通讯录全没了…… |
/system |
系统分区:Android 框架、系统应用、原生库 | 只读(除非刷机或 remount) | 早期我尝试直接修改 /system/build.prop 改屏幕密度,结果变砖了 |
/sdcard |
共享存储:照片、下载文件、App 外部数据 | 普通应用可读写(需权限) | 这个目录其实是 /data/media/0 的软链接,别搞混了 |
/vendor |
厂商定制分区:驱动、硬件相关库 | 通常只读 | 调试相机 HAL 时经常需要看这里 |
/proc |
虚拟文件系统:进程信息、内核参数 | 只读(部分文件可写) | 查看 /proc/cpuinfo 可以快速确认芯片型号 |
核心原则:/data 是用户数据的命根子,/system 是系统的骨架,/sdcard 是用户看得见摸得着的文件。调试时,90% 的操作都在 /data 和 /sdcard 上。
11.2 文件操作四剑客:mkdir、rm、mv、chmod
这四个命令,是我在 adb shell 里用得最频繁的。说白了,它们就是你在 Linux 终端里吃饭的家伙。但 Android 环境有些特殊限制,我一个个说。
11.2.1 mkdir —— 创建目录
语法很简单:mkdir [-p] 目录路径。那个 -p 参数,我建议你每次都带上。为什么?
我曾经在写自动化测试脚本时,想创建 /data/local/tmp/test/logs 这个目录。如果父目录 test 不存在,直接 mkdir /data/local/tmp/test/logs 会报错。加上 -p 后,它会自动创建所有不存在的父目录。
# 创建单层目录
adb shell mkdir /data/local/tmp/myapp
# 创建多层目录(推荐)
adb shell mkdir -p /data/local/tmp/myapp/logs/2024
# 验证
adb shell ls -l /data/local/tmp/myapp/
小技巧:在 /data/local/tmp/ 下创建目录,是 shell 用户最安全的操作区域。这里既不会被普通应用干扰,也不会误伤系统文件。
11.2.2 rm —— 删除文件或目录
这个命令要格外小心。我见过太多人(包括我自己早期)在 adb shell 里手滑删错东西。
# 删除单个文件
adb shell rm /sdcard/test.txt
# 删除目录及其所有内容(-r 递归,-f 强制)
adb shell rm -rf /data/local/tmp/myapp
# 安全删除:先确认再动手
adb shell ls -l /data/local/tmp/myapp
# 确认无误后
adb shell rm -rf /data/local/tmp/myapp
警告:千万不要在 /data、/system 根目录下执行 rm -rf!我曾经在调试一台旧设备时,想清理 /data/dalvik-cache,结果路径写成了 /data 后面少了个斜杠……嗯,那台设备直接开不了机了。
11.2.3 mv —— 移动或重命名
mv 既可以移动文件,也可以重命名。在 Android 上,它比 cp 更常用,因为 mv 不涉及文件内容拷贝,速度快,而且不占用额外存储空间。
# 重命名文件
adb shell mv /sdcard/old_name.txt /sdcard/new_name.txt
# 移动文件到另一个目录
adb shell mv /sdcard/test.txt /data/local/tmp/
# 移动并重命名
adb shell mv /sdcard/test.txt /data/local/tmp/new_test.txt
这里有个坑:mv 不能跨文件系统移动。什么意思?/data 和 /sdcard 虽然看起来都在同一个设备上,但它们可能挂载在不同的分区。如果你尝试 mv /data/local/tmp/test.txt /sdcard/,在某些设备上会报错。这时候你得用 cp 然后 rm。
11.2.4 chmod —— 修改文件权限
Android 的权限模型基于 Linux 的 rwx(读、写、执行)三组权限:所有者、所属组、其他人。
# 查看当前权限
adb shell ls -l /data/local/tmp/test.sh
# 输出示例:-rw-rw---- 1 shell shell 1024 Jan 1 12:00 test.sh
# 解读:所有者(shell)可读写,组(shell)可读写,其他人无权限
# 添加执行权限
adb shell chmod +x /data/local/tmp/test.sh
# 设置精确权限(755:所有者全部权限,组和其他人只读+执行)
adb shell chmod 755 /data/local/tmp/test.sh
# 设置 777(不推荐,但调试时偶尔用)
adb shell chmod 777 /sdcard/test.txt
权限数字速查表:
- 644:文件默认权限,所有者可读写,其他人只读
- 755:可执行文件或目录,所有者全部权限,其他人只读+执行
- 777:所有人全部权限(安全风险,别在生产环境用)
- 600:仅所有者可读写(适合存放密钥、密码文件)
11.3 实战:用 adb shell 完成一次完整的文件操作流程
光说不练假把式。我拿一个真实场景举例:调试一个 App 的日志输出问题。
# 1. 进入 shell
adb shell
# 2. 创建调试目录
mkdir -p /data/local/tmp/debug_logs
# 3. 从 App 的数据目录复制日志文件(需要 root 或 run-as)
run-as com.example.myapp
cp /data/data/com.example.myapp/files/log.txt /data/local/tmp/debug_logs/
exit
# 4. 修改权限,方便后续拉取到电脑
chmod 644 /data/local/tmp/debug_logs/log.txt
# 5. 重命名文件,加上时间戳
mv /data/local/tmp/debug_logs/log.txt /data/local/tmp/debug_logs/log_2024_01_01.txt
# 6. 退出 shell,拉取到电脑
exit
adb pull /data/local/tmp/debug_logs/log_2024_01_01.txt ./
这套流程,我几乎每周都要走一遍。熟练之后,从发现问题到拿到日志,不超过 30 秒。
11.4 文件系统结构图:一张图看懂 Android 存储
下面这张图,是我自己总结的 Android 文件系统核心结构。你把它记在脑子里,以后调试时就能快速定位问题。
11.5 避坑指南:我这些年踩过的文件操作坑
最后,分享几个真实教训。你遇到了,至少知道问题出在哪。
- 权限不足导致操作失败:在
/data/data/下操作时,如果没有 root 权限,很多目录你连ls都执行不了。这时候用run-as 包名或者adb shell后先su。 - 路径中的空格:Android 的
/sdcard下经常有带空格的目录名,比如My Documents。记得用引号包起来:adb shell ls "/sdcard/My Documents"。 - 软链接与真实路径:
/sdcard在很多设备上是指向/data/media/0的软链接。如果你用df -h查看空间,会发现/data和/sdcard其实是同一块分区。别被迷惑了。 - chmod 对 /sdcard 无效:
/sdcard通常是 vfat 或 sdcardfs 文件系统,不支持 Linux 权限位。你执行chmod 777 /sdcard/test.txt不会报错,但实际权限不会改变。
嗯,文件操作这块,说白了就是多练。你可以在自己的测试机上随便折腾,只要不动 /data 和 /system 的核心文件,一般不会出大问题。但生产环境——我建议你三思而后行。