Kotlin中执行Root权限ADB命令开关飞行模式失效问题咨询
问题根因
你写的Root执行代码存在两个核心问题,导致命令虽然触发了Root授权,但实际没有正确执行:
- 命令参数解析错误:
Runtime.getRuntime().exec()不会像ADB Shell环境那样自动解析单引号/双引号等Shell语法,它默认按空白字符拆分传入的整条字符串为命令参数。你写的su -c 'settings put global airplane_mode_on 1'会被拆分为su、-c、'settings、put、global、airplane_mode_on、1'几个参数,等于传给su执行的命令是首尾带多余单引号的无效字符串,系统根本找不到名为'settings的可执行文件,命令直接执行失败。你看到的超级用户授权Toast只是证明su进程被成功唤起,不代表后续传入的命令能正常运行。 - 进程上下文隔离:你两次单独调用
exec()会启动两个完全独立的Root权限进程,两个进程的Shell会话不互通,部分定制ROM会对跨会话的系统设置修改、系统广播发送做额外权限校验,就算第一条命令修改了设置值,第二条广播也可能因为上下文不匹配被系统拦截。同时你没有读取命令的执行返回和错误流,完全感知不到执行报错。
另外补充:Android 4.2及以上版本发送飞行模式变更广播时,必须携带--ez state 布尔值的附加参数,否则部分厂商ROM的系统服务不会响应广播切换飞行模式状态,你ADB执行时没加参数能生效是因为部分旧版系统兼容了无参数的广播,不代表应用内执行也能兼容。
正确实现代码
不要使用带单引号的su -c 'xxx'写法,推荐直接获取su进程的输出流,将所有待执行命令一次性写入同一个Root Shell会话执行,避免参数拆分错误和进程隔离问题,Kotlin实现代码如下:
// 启动Root权限进程 val suProcess = Runtime.getRuntime().exec("su") // 获取进程输出流,用于向Root Shell写入待执行命令 val commandWriter = suProcess.outputStream.bufferedWriter() // 1. 写入全局配置,设置飞行模式为开启状态(值为0则是关闭) commandWriter.write("settings put global airplane_mode_on 1\n") // 2. 写入广播发送命令,携带state参数通知系统状态变更 commandWriter.write("am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true\n") // 写入退出命令结束Shell会话 commandWriter.write("exit\n") commandWriter.flush() // 等待命令执行完成,获取执行返回码,返回0代表执行成功 val execResult = suProcess.waitFor() commandWriter.close() // 调试阶段可以读取suProcess.errorStream的内容,打印排查执行报错
额外注意事项
- 不要多次单独调用
exec()启动多个su进程执行多条关联命令,既会重复触发Root权限校验,也容易出现上下文隔离导致的执行失败。 - 如果需要关闭飞行模式,只需要把
airplane_mode_on的值改为0,同时把广播参数里的true改为false即可。 - 部分Android 10+的定制ROM加强了飞行模式的权限管控,就算有Root权限,部分场景下发送广播也可能被系统拦截,这种情况可以尝试调用系统服务的隐藏API实现,不过Root环境下上述Shell命令方案在绝大多数设备上都可正常生效。
内容的提问来源于stack exchange,提问作者Rest0rer
相关产品推荐
相关产品推荐

