十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Android文件权限管理:adb chmod/chown命令详解与实战

Android文件权限管理:adb chmod/chown命令详解与实战 1. 从一次文件删除失败说起为什么需要adb修改权限那天下午我正试图清理一台测试用的安卓设备里面塞满了各种临时文件和过期的日志。我通过USB连接电脑用adb shell进入系统找到了一个名为/data/local/tmp/test_crash.log的旧文件想用rm命令把它删掉。结果终端无情地返回了一行错误rm: /data/local/tmp/test_crash.log: Permission denied。这个场景相信任何一个和安卓设备打过交道的开发者或极客都遇到过。你明明已经通过adb shell进入了设备的命令行环境理论上拥有了一个“shell”用户的权限但为什么连删除一个自己创建或系统生成的临时文件都做不到这背后牵扯到的就是安卓系统基于Linux内核的文件权限和用户/用户组管理体系。而adb作为我们与设备系统深度交互的“桥梁”其权限级别直接决定了我们能做什么、不能做什么。简单来说adbAndroid Debug Bridge本身是一个客户端-服务器程序它包含三个核心组件运行在PC端的客户端adb命令、运行在PC端作为后台进程的服务器adb server以及运行在安卓设备或模拟器上的守护进程adbd。当我们执行adb shell时我们启动的是一个在设备上以shell用户身份运行的交互式终端。这个shell用户在大多数非root的设备上其权限是受到严格限制的它不属于root超级用户组也无法直接访问或修改许多系统关键目录如/system和受保护的用户数据目录如/data/data/下的应用私有数据。因此当我们需要修改一个文件的权限例如让一个脚本可执行或者让一个应用能读取某个配置文件或者需要访问/修改一个当前用户无权操作的文件时就必须借助一些方法。这些方法的核心要么是提升adb shell的权限至root要么是使用adb命令以更高的权限直接对文件进行操作。这就是“adb修改文件权限”这个标题背后所指向的核心需求突破默认的权限限制完成对设备文件系统的特定操作。接下来的内容我将为你彻底拆解如何利用adb完成文件权限的查看与修改。这不仅包括基础的chmod命令更会深入探讨在不同设备状态root/非root下的策略选择、处理“Permission denied”的实战思路以及如何安全、有效地进行权限管理。无论你是应用开发者需要在真机上调试权限问题还是发烧友想折腾自己的设备这些内容都将是你工具箱里的必备利器。2. 理解基石Linux文件权限模型与adb shell的权限上下文在动手敲命令之前我们必须先打好理论基础。安卓系统底层是Linux因此其文件权限模型完全继承自Linux。理解这个模型是解决一切权限问题的前提。2.1 文件权限的“三元组”与“九字符”在Linux中每个文件和目录都有三组权限分别对应三种身份文件所有者Owner创建该文件的用户。所属用户组Group文件所属的用户组。其他用户Others既不是所有者也不在所属组里的其他所有用户。对于每一种身份都有三种基本的权限类型r (Read读)对于文件意味着可以查看内容对于目录意味着可以列出目录内的文件列表。w (Write写)对于文件意味着可以修改内容对于目录意味着可以在其中创建、删除、重命名文件。x (eXecute执行)对于文件意味着可以作为程序或脚本运行对于目录意味着可以“进入”该目录即cd到该目录并访问其中的文件元数据。如何查看这些权限使用adb shell进入设备后运行ls -l命令。你会看到类似这样的输出-rw-rw---- 1 shell shell 4096 2023-10-01 10:30 myfile.txt drwxr-xr-x 2 root root 4096 2023-10-01 10:30 mydir/第一列就是权限字符串。以-rw-rw----为例第一个字符-表示这是一个普通文件d表示目录l表示链接等。接下来的三个字符rw-表示文件所有者的权限可读、可写但不可执行。再三个字符rw-表示所属用户组的权限同样可读、可写不可执行。最后三个字符---表示其他用户的权限无任何权限。这就是常说的“九位权限字符”。有时你会看到用数字表示如755、644这是八进制表示法将每组rwx转换为一个数字r4, w2, x1求和。rwxr-xr-x就是755所有者7组5其他5。2.2 adb shell的默认身份shell用户当你输入adb shell并成功进入后命令行提示符通常是$而非#。这个$提示符意味着你当前的身份是非root用户在安卓上通常是shell用户。你可以用whoami命令确认$ whoami shell再用id命令查看更详细的身份信息$ id uid2000(shell) gid2000(shell) groups2000(shell),1004(input),1007(log),1011(adb),...这告诉我们当前进程的有效用户IDuid是2000即shell用户有效组IDgid也是2000即shell组。同时还属于input、log、adb等其他辅助组。关键点来了shell用户的权限是受限的。它无法访问属于root用户或system用户的文件除非这些文件对“其他用户”开放了相应权限也无法修改大多数系统目录的权限。这就是开头那个Permission denied错误的根源——test_crash.log文件的所有者或所属组可能不是shell且没有给“其他用户”写权限所以shell用户无法删除它。2.3 权限检查流程系统如何决定说“是”或“否”当进程比如rm命令对应的进程试图访问一个文件时Linux内核会按以下顺序检查如果进程的uid是0root则通常直接放行有一些更细粒度的安全模块如SELinux可能会干预但基础权限模型如此。如果进程的uid等于文件的所有者uid则应用“所有者”权限位。如果进程的gid或任一附加组gid等于文件的所属组gid则应用“所属组”权限位。否则应用“其他用户”权限位。在我们的例子中rm进程以shelluid2000身份运行。如果test_crash.log的所有者是rootuid0所属组是shellgid2000权限是rw-rw----660。那么检查过程是uid不匹配2000 ! 0- 检查组发现进程的gid2000匹配文件的所属组gid2000- 应用“所属组”权限rw-- 有写权限删除操作应该成功。但如果文件权限是rw-r-----640那么“所属组”只有读权限没有写权限删除就会失败。因此遇到权限问题第一步永远是ls -l查看文件的权限和归属再用id查看自己的身份然后根据上述规则进行比对。这是所有后续操作的诊断基础。3. 核心武器chmod、chown命令详解与实战理解了权限模型我们就可以使用工具来修改它。最核心的两个命令是chmod改变模式和chown改变所有者。3.1 使用chmod修改文件权限chmod命令用于修改文件的权限位。其基本语法有两种形式1. 符号模式相对模式使用u所有者、g组、o其他、a全部和添加、-移除、设置进行操作直观易懂。adb shell chmod [选项] 模式 文件或目录示例1给文件所有者添加执行权限$ adb shell chmod ux /data/local/tmp/myscript.sh执行后如果原权限是rw-r--r--644则会变为rwxr--r--744。示例2移除组和其他用户的写权限$ adb shell chmod go-w /data/local/tmp/somefile.txt示例3设置目录为所有者可读写执行组可读执行其他用户无权限$ adb shell chmod urwx,grx,o /data/local/tmp/myapp/这等价于数字模式750。2. 数字模式绝对模式直接使用八进制数字设置权限精确且高效。adb shell chmod [选项] 八进制数字 文件或目录示例将文件权限设置为644所有者读写组只读其他只读$ adb shell chmod 644 /data/local/tmp/config.json这是Web服务器配置文件、普通数据文件最常见的权限。示例将脚本权限设置为755所有者读写执行组读执行其他读执行$ adb shell chmod 755 /data/local/tmp/start_server.sh这使得任何用户都可以执行这个脚本但只有所有者能修改。注意修改权限本身也是一个需要权限的操作你必须对目标文件拥有写权限如果你是所有者或者是root用户。如果你以shell用户身份尝试修改一个属于root且权限为644的文件你会再次得到Permission denied。这时你就需要更高权限的adb shell环境。常用选项-R或--recursive递归地修改目录及其内部所有文件和子目录的权限。使用时要极其小心错误的递归权限修改可能导致系统或应用无法运行。// 危险操作示例切勿随意在系统目录执行 $ adb shell chmod -R 777 /system3.2 使用chown改变文件所有者和所属组chown命令用于更改文件的所有者和/或所属组。其基本语法为adb shell chown [选项] 所有者[:所属组] 文件或目录示例1将文件的所有者改为root$ adb shell chown root /data/local/tmp/important.pem示例2将文件的所有者和所属组都改为system$ adb shell chown system:system /data/local/tmp/socket_node示例3仅更改文件的所属组为shell$ adb shell chown :shell /data/local/tmp/shared.log重要限制在非root的adb shell环境下chown命令几乎无法使用。因为将文件的所有权转移给其他用户是一项特权操作通常只有root用户才能执行。如果你以shell身份运行chown大概率会失败。因此chown的使用通常与获取root权限的adb shell紧密相关。3.3 实战场景让一个脚本可执行并运行假设你在/data/local/tmp/下有一个Python脚本backup.py你通过adb push上传后发现无法运行。$ adb shell ls -l /data/local/tmp/backup.py -rw-rw-r-- 1 shell shell 1529 2023-10-01 11:00 backup.py $ adb shell /data/local/tmp/backup.py /system/bin/sh: /data/local/tmp/backup.py: can‘t execute: Permission denied错误信息很明确权限被拒绝无法执行。查看权限发现所有者和组都有读写权限rw-但没有执行权限x。解决方案添加执行权限。由于你是所有者shell你可以直接修改。$ adb shell chmod ux /data/local/tmp/backup.py或者如果你希望所有用户都能执行比如这是一个工具脚本$ adb shell chmod 755 /data/local/tmp/backup.py再次检查权限并运行。$ adb shell ls -l /data/local/tmp/backup.py -rwxrw-r-- 1 shell shell 1529 2023-10-01 11:00 backup.py $ adb shell /data/local/tmp/backup.py 脚本开始执行...如果脚本有Shebang如#!/usr/bin/env python3系统会自动调用对应的解释器。如果没有你需要显式指定adb shell python3 /data/local/tmp/backup.py。4. 权限提升之路获取root shell的多种方法与局限当shell用户的权限不够时我们自然想到获取root权限。但请注意在当今的安卓设备上尤其是较新的版本和大多数品牌机上获取完整的、持久的root权限非常困难且可能使设备失去保修、引入安全风险。以下方法更多用于开发调试、已解锁/已root的设备或模拟器。4.1 adb root命令最直接的方式需设备支持如果设备的adbdadb守护进程编译时支持并且当前以root身份运行你可以直接使用adb root这个命令会重启adbd并以root权限运行。成功后再执行adb shell你会看到提示符变为#表示你已处于rootshell中。C:\ adb root restarting adbd as root C:\ adb shell device_name:/ #在这个环境下你可以执行几乎任何文件操作命令chmodchownrmmount等不再受普通权限限制。然而现实很骨感绝大多数消费级手机出厂时adbd都是以非root身份运行的。执行adb root通常会返回adbd cannot run as root in production builds。这个功能主要存在于工程机、某些系统的调试版本或已刷入具有root权限adbd的自定义ROM的设备上。4.2 adb shell su通过SuperSU/Magisk切换在已经通过Magisk或旧版SuperSU等工具获取了root权限的设备上虽然adbd本身不是root但shell用户可以通过suswitch user命令切换到root。adb shell $ su #执行su后通常会弹出授权请求如果你使用了Magisk Manager在设备上点击“允许”后PC端的adb shell就会获得root权限。这是目前移动设备上最主流的root权限使用方式。4.3 模拟器与开发设备通常自带root对于Android Studio自带的AVDAndroid Virtual Device以及像MuMu、夜神这样的第三方模拟器它们通常默认就开启了root权限。你可以在模拟器设置中确认或者直接尝试adb root或adb shell su。这也是为什么开发者更喜欢在模拟器上测试需要高权限操作的原因。4.4 临时提权技巧run-as命令的妙用对于已调试的应用即应用清单中android:debuggabletrue且通过USB调试安装有一个非常实用的命令run-as。这个命令允许shell用户以指定应用的用户身份运行命令。由于每个应用在安装时都会被分配一个唯一的Linux用户ID通常像u0_a123应用的数据目录/data/data/package_name归这个用户所有。shell用户无法直接访问但run-as可以。adb shell $ run-as your.package.name成功后会进入一个受限的shell其当前用户就是该应用的用户。此时你可以访问和修改该应用自己的数据文件。$ run-as com.example.myapp $ ls -l /data/data/com.example.myapp/files/ $ cat /data/data/com.example.myapp/shared_prefs/config.xml $ echo new config /data/data/com.example.myapp/files/test.txt重要限制run-as只能用于访问该应用自身的数据文件。你不能用它来修改系统文件或其他应用的文件。它的主要用途是调试、查看或修改自己开发的App的私有数据而无需root权限。这是一个被严重低估的调试利器。4.5 没有root时的迂回策略利用adb push/pull和临时目录如果设备没有root你又需要修改一个shell用户无权修改的系统文件比如只读的/system分区下的文件该怎么办通常直接修改是不可能的。但有一些迂回方案修改副本并替换需解锁System分区对于已解锁system分区的设备你可以adb pull /system/etc/hosts .拉取文件到电脑。在电脑上修改这个副本。adb remount重新挂载/system为可写这步需要root或工程模式。adb push hosts /system/etc/hosts推送回去。这本质上还是需要高权限环境adb remount。修改/data/local/tmp下的文件这是shell用户通常具有完全读写权限的目录rwxrwx--x或rwxrwxrwx。你可以把需要修改或执行的脚本、配置文件放在这里。许多需要临时文件的操作都可以在这个目录下完成。核心原则在没有root的情况下你的操作被严格限制在shell用户的权限沙盒内。优先考虑使用/data/local/tmp或者利用run-as访问自己的应用数据。试图突破这个沙盒去修改系统文件在未root的设备上基本行不通。5. 实战排查层层递进解决“Permission denied”现在让我们整合前面的知识构建一个系统性的排查流程用于解决最常见的adb操作中的“Permission denied”错误。假设我们想删除文件/data/misc/old_config.xml。步骤1确认当前adb shell权限$ adb shell $ whoami shell $ id uid2000(shell) gid2000(shell) groups2000(shell),...确认是shell用户。步骤2查看目标文件的详细权限和归属$ ls -l /data/misc/old_config.xml -rw-r----- 1 system misc 1024 2023-09-15 08:00 /data/misc/old_config.xml分析所有者system所属组misc权限rw-r-----(640)。所有者system可读写组misc可读其他用户无任何权限。步骤3比对当前用户身份与文件权限当前用户是shelluid2000。文件所有者是systemuid1000不同系统可能不同但肯定不是2000所以不匹配“所有者”权限。当前用户所属组是shellgid2000文件所属组是miscgid999id命令显示shell用户不在misc组内所以不匹配“所属组”权限。因此应用“其他用户”权限位---即无任何权限。结论shell用户无权删除此文件。步骤4评估可用的提权路径尝试adb root在命令行执行adb root。如果返回adbd cannot run as root...此路不通。尝试su在adb shell中执行su。如果提示/system/bin/sh: su: not found或请求被拒绝此路不通。检查是否可用run-as此文件不属于任何一个应用的数据目录run-as无效。检查文件位置文件在/data/misc/这通常是一个系统管理的目录shell用户默认无写权限。步骤5根据评估结果采取行动情况A设备已root或为模拟器通过su或adb root获得#提示符后直接执行rm /data/misc/old_config.xml。情况B设备未root但文件可移动如果文件不重要或者你的目的只是清理空间而文件在/data/misc/下这通常是系统进程管理的。不建议强行删除可能会引发系统不稳定。如果这是你自己测试产生的垃圾文件最好的做法是重启设备或者停止相关服务后再删除。情况C需要修改文件内容而非删除如果目标是修改这个配置文件在未root的情况下几乎不可能。你需要寻找其他配置方式或者该配置是否有通过API或settings命令修改的渠道。步骤6记录与验证如果操作成功再次ls -l确认文件已消失。如果操作涉及权限修改chmod操作后再次ls -l确认权限已按预期更改。这个流程的核心是先诊断whoami ls -l再分析比对权限最后选择正确的工具或路径提权、迂回或放弃。盲目尝试sudo安卓上通常没有或寻找各种“强制删除”的偏方往往是徒劳的。6. 高级应用与深度注意事项掌握了基础操作和排查流程后我们来看一些更深入的应用场景和容易踩坑的地方。6.1 修改目录权限的特殊性X权限位当对目录使用chmod时执行位x的含义与文件不同。对于目录x权限意味着“可进入/可搜索”。如果没有x权限即使有r权限也无法列出目录内容如果没有x权限即使有w权限也无法在目录内创建或删除文件。// 创建一个目录并设置奇怪权限 $ adb shell mkdir /data/local/tmp/test_dir $ adb shell chmod 644 /data/local/tmp/test_dir // 目录权限为 rw-r--r-- $ adb shell ls -l /data/local/tmp/ drw-r--r-- 2 shell shell 4096 ... test_dir // 注意第一个字符是‘d’ $ adb shell ls /data/local/tmp/test_dir ls: ./test_dir: Permission denied // 有r权限但无x权限无法列出内容 $ adb shell touch /data/local/tmp/test_dir/file.txt touch: /data/local/tmp/test_dir/file.txt: Permission denied // 无x权限无法创建文件因此在设置目录权限时如果希望用户能访问目录内的内容通常需要赋予x权限。常见的目录权限是755rwxr-xr-x或775rwxrwxr-x。6.2 SELinux上下文另一道安全防线在现代安卓系统尤其是Android 5.0上仅有传统的Linux DAC自主访问控制权限是不够的。SELinux安全增强型Linux作为MAC强制访问控制层实施了更细粒度的安全策略。即使你是root用户DAC检查通过SELinux策略也可能拒绝你的操作。你可以通过ls -Z查看文件或进程的SELinux上下文$ adb shell ls -Z /data/local/tmp/testfile u:object_r:shell_data_file:s0 /data/local/tmp/testfile如果遇到权限拒绝而DAC检查明明通过了可以查看logcat日志搜索avc: denied来获取SELinux拒绝的详细信息。adb logcat -d | grep avc:.*denied在已root的调试设备上可以临时将SELinux设置为宽容模式来测试是否是SELinux导致的问题adb shell su -c “setenforce 0” // 设置为Permissive模式注意生产环境中切勿禁用SELinux这会极大降低系统安全性。测试完毕后记得改回adb shell su -c “setenforce 1” // 设置为Enforcing模式6.3 通过adb install安装APK时的权限问题adb install命令本身不需要shell用户对系统应用目录有写权限因为它通过adb守护进程adbd与系统的installd服务通信由installd通常以root或system权限运行来完成实际的安装工作。所以常见的adb install失败错误如INSTALL_FAILED_INSUFFICIENT_STORAGE、INSTALL_FAILED_UPDATE_INCOMPATIBLE等与文件权限无关。但是如果你尝试安装到特定位置比如使用adb install -s安装到SD卡或者尝试adb push一个APK到/system/app/然后重启就会遇到严重的权限问题。后者需要root权限和可写的/system分区。6.4 批量操作与脚本中的权限处理在编写通过adb shell执行的脚本时务必注意权限的继承和设置。例如一个常见的模式是adb push setup.sh /data/local/tmp/adb shell chmod 755 /data/local/tmp/setup.shadb shell /data/local/tmp/setup.sh在setup.sh脚本内部如果它创建了新的文件或目录需要显式地用chmod或chown来设置合适的权限否则新创建的文件可能会继承脚本运行环境的默认权限通常由umask决定可能导致后续步骤失败。6.5 模拟器与真机的差异在模拟器如AVD、MuMu、夜神上进行adb权限操作通常比真机简单得多因为它们大多默认开启root访问。这提供了一个理想的沙盒环境。一个重要的实践是先在模拟器上验证你的adb脚本和权限修改逻辑确认无误后再在有条件的真机上谨慎测试。真机的系统分区通常是只读的并且SELinux策略更为严格。例如在MuMu模拟器中你通常可以直接adb root。而在真机上同样的命令会失败。你的脚本或操作流程需要能处理这种差异例如通过尝试adb root并检查返回值或者先尝试su来判断环境。7. 安全警告与最佳实践操作文件权限尤其是获取root权限后权力越大责任越大风险也越高。永远不要随意运行来历不明的脚本或命令特别是要求root权限的。一个rm -rf /system命令就足以让你的设备变砖。修改系统文件前先备份在尝试修改/system、/vendor等分区下的任何文件前务必先adb pull备份原文件。很多系统文件相互依赖修改一个可能导致无法开机。谨慎使用chmod -R和chown -R递归修改权限是极其危险的操作。一旦在错误目录如/、/system、/data执行了类似chmod -R 777整个系统的权限体系将崩溃几乎只能通过重新刷机来挽救。理解修改的目的不要为了消除一个Permission denied错误而盲目地将文件权限改为777所有人可读可写可执行。这破坏了最小权限原则可能引入安全漏洞。应该思考这个文件应该被谁访问然后只赋予必要的权限。例如一个配置文件可能只需要644所有者可写其他人只读。利用应用沙盒对于应用数据优先使用run-as来访问和调试而不是总想着获取全局root。这更安全也符合安卓的设计哲学。生产环境与开发环境分离不要在用于日常通讯、支付的主力机上轻易进行root或高风险的权限修改操作。使用专门的测试机或模拟器。在我多年的开发和调试经历中因为权限问题导致的“灵异事件”数不胜数。有时是脚本忘了加执行权限有时是目录没有x权限导致文件无法创建还有时是SELinux策略突然收紧导致之前能用的adb命令失效。解决问题的关键始终是冷静地回到起点ls -l、whoami、id然后像侦探一样分析权限矩阵。adb修改文件权限这个看似简单的主题背后串联起的是Linux基础、安卓系统安全和实际调试经验。掌握它你就能更从容地驾驭你的安卓设备无论是真机还是模拟器。
返回列表