Android- 以编程方式执行 su 命令不起作用

Android- performing su commands programatically does not work

我需要我的应用程序以编程方式执行一些 su 命令(phone 已植根)。

使用 adb 完成后,命令有效。

例如: su -c "mkdir /sdcard/testdir" 在 /sdcard 中创建一个名为 "testdir" 的目录。

当我打电话时:

    p = Runtime.getRuntime().exec("su -c \"mkdir /sdcard/testdir\"");
    p.waitFor();

它只是继续前进,没有任何变化发生。

我尝试读取输入:

DataInputStream dis = new DataInputStream(p.getInputStream());
    while((temp = dis.readLine())!=null)
        Log.d(ctx.TAG,"shell:"+temp);

但它什么也没报告(循环执行 0 次迭代)。

有没有人遇到过这个问题?如何解决? 不用说,非 su 命令确实可以使用此方法以编程方式工作。

注意:我以mkdir为例(我知道它不一定需要su)。我需要在 su

下执行很多不同的命令

谢谢!

编辑:当我以编程方式调用 su -c "id" 时,输出 uid=0.

您可能在主线程中调用 Runtime.getRuntime().exec() 并且 p.waitFor() 让您的主线程等待直到它执行。尝试在另一个线程中调用,例如以下代码段。

new Thread(){

     @override
     public void run(){
        p = Runtime.getRuntime().exec("su -c \"mkdir /sdcard/testdir\"");
        p.waitFor();

     }.start();

}

我可能会在一个问题上卡上好几天,当我鼓起勇气在 Whosebug 上提问时,它会在几分钟内解决。

修复方法是:

    p=Runtime.getRuntime().exec("su");
    DataOutputStream dos = new DataOutputStream(p.getOutputStream());
    dos.writeBytes("mkdir /sdcard/testdir\n");
    dos.writeBytes("exit\n");
    dos.flush();
    dos.close();
    p.waitFor();

不要忘记在每个写入 DataOutputStream 的命令末尾添加 \n,因为没有它它将无法工作。

你写的是你"need varied commands to be performed under su"。请注意,最著名的 SuperSU 根应用程序的开发者 Chainfire 不鼓励使用 "Runtime.exec()"。

It is tempting to use Runtime.getRuntime().exec("su -c [command]");, but you should be aware that [command] should be a single parameter, and thus may require quoting. Unfortunately both quoting the [command] parameter as well as passing the paramaters as separate variables to either Runtime.exec() or ProcessBuilder does not work consistently across all Android versions, and thus this construct should be avoided entirely. It is not impossible to do this right - but there's a high risk of problems.

请参阅 How to SU 文档。所以你可能想在这里遵循他的建议:

3.2. Making the call

A common method to call su that avoids the known issues listed above is by creating an interactive shell and piping commands to it. This is done by calling Runtime.getRuntime().exec("su");, and retrieving input and output streams from the returned Process object. Doing this is a fairly straight-forward piece of code, but including the debug logs and checks it's a bit long to reproduce here.

The core code is located here: [libsuperuser :: Shell.java @ GitHub]. Shell.run() is a generic call to run shell code, the following more specific (static) utility functions are the ones you will probably end up using:

List<String> Shell.SH.run(String command)
List<String> Shell.SH.run(List<String> commands)
List<String> Shell.SH.run(String[] commands)

List<String> Shell.SU.run(String command)
List<String> Shell.SU.run(List<String> commands)
List<String> Shell.SU.run(String[] commands)

The SH variants are used for a non-root shell, where the SU variants are used for a root shell. These calls return a List containing the output of the shell commands. If there was no output, the list is empty, but not null. The result is only null in case an error occured - including the user not granting your app su access. These are blocking calls.

Note that in debug compiles, all shell STDIN/STDOUT/STDERR will be logged to logcat, and these calls will (intentionally) crash your app if called from the main thread. The reason for this will be discussed in section 4. When to call su.

如果你使用双引号,它会起作用:

su -c ""command with args""