Android 12中Magisk Root应用执行su命令仅返回部分包名求助
Android 12下Magisk Root应用无法读取完整/data/data目录的原因及解决方法
问题根源
Android 12进一步强化了应用存储沙箱与挂载命名空间隔离机制:
- 普通App调用
su时,默认会继承自身的挂载命名空间,该命名空间内的/data/data经过沙箱过滤,仅能看到自身应用及系统公共应用(如com.google.android.gms)的目录。 - 终端模拟器启动的
su会直接切换到全局挂载命名空间(对应系统init进程的命名空间),因此能看到所有应用的data目录。 - Android 10的存储隔离机制未做如此严格的限制,Magisk的
su调用默认进入全局命名空间,所以可以正常获取完整结果。
解决方案
1. 强制切换到全局挂载命名空间执行命令
在命令中加入命名空间切换指令,确保在全局视图下读取目录:
执行的命令修改为:
nsenter --mount=/proc/1/ns/mnt ls /data/data
nsenter工具可让进程进入指定的系统命名空间,/proc/1/ns/mnt是系统init进程的挂载命名空间,对应全局文件系统视图。
2. 优化su命令调用逻辑
避免通过向su进程输入命令的方式执行,改用su -c直接传递命令参数,这种方式能确保命令在正确的Superuser环境下运行,稳定性更高:
替换原代码中的命令执行方法,使用如下实现:
public static String executeCommand(String[] cmd) { try { Process process = new ProcessBuilder(cmd).start(); // 等待命令执行完成,替代固定sleep的不可靠方式 process.waitFor(); // 读取错误输出 BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream())); StringBuilder errSb = new StringBuilder(); String line; while ((line = errReader.readLine()) != null) { errSb.append(line).append("\n"); } String errOutput = errSb.toString(); if (!errOutput.trim().isEmpty()) { Log.e("SystemHelper", "Error: " + errOutput); } // 读取标准输出 BufferedReader outReader = new BufferedReader(new InputStreamReader(process.getInputStream())); StringBuilder outSb = new StringBuilder(); while ((line = outReader.readLine()) != null) { outSb.append(line).append("\n"); } String output = outSb.toString(); Log.i("SystemHelper", "Output: " + output); return output; } catch (IOException | InterruptedException e) { Log.e("SystemHelper", "Command execute failed", e); return ""; } }
在onCreate中调用该方法:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); requestPermission(); String s = executeCommand(new String[]{"su", "-c", "nsenter --mount=/proc/1/ns/mnt ls /data/data"}); Log.i("vvvvv", s); Toast.makeText(getApplicationContext(), "Result: " + s, Toast.LENGTH_LONG).show(); }
3. 清理无效权限
Manifest中的ACCESS_SUPERUSER是旧版SuperSU的权限,Magisk并不依赖该权限,直接删除即可,避免不必要的混淆。
关键修正点说明
- 用
process.waitFor()替代SystemClock.sleep(3000):固定sleep时间无法适配不同设备的命令执行速度,waitFor()会等待进程执行完毕后再读取输出,结果更可靠。 - 采用数组传递命令参数:避免命令字符串被shell解析时出现异常,同时确保
su直接接管命令的执行环境。
内容的提问来源于stack exchange,提问作者Defi Nghĩa
相关产品推荐
相关产品推荐

