从Android应用程序中的busybox命令获取输出

时间:2012-04-09 03:42:26

标签: android shell loops busybox su

对于我的生活,我无法让我的应用程序从su shell中调用busybox的进程获得响应。

我尝试了三种不同的方法,并尝试了三种方法的组合以使其工作,但我永远无法从使用busybox的任何东西获得输出,只有其他命令。

更具体地说,我可以让它返回像“ls / data”和“cat suchandsuch.file”这样的命令,但任何以“busybox”开头的东西(即busybox mount,busybox free)都不会显示任何内容。

这是最接近我的方法,此代码使用“ls / data”,但不是“busybox free”

这个将运行命令(大部分),并从输入流中无限循环返回一个空字符串。

        Process p;
        try {
            p = Runtime.getRuntime().exec(new String[]{"su", "-c", "/system/bin/sh"});
        DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
        stdin.writeBytes("ls /data\n");
        DataInputStream stdout = new DataInputStream(p.getInputStream());
        byte[] buffer = new byte[4096];
        int read = 0;
        String out = new String();
        while(true){
            read = stdout.read(buffer);
            out += new String(buffer, 0, read);
            if(read<4096){
                break;
            }
        }
        Toast.makeText(getApplicationContext(), out, Toast.LENGTH_SHORT).show();
        } catch (IOException e) {
            e.printStackTrace();
        }

底部附近的吐司显示“ls / data”中的所有内容,但是当更改为busybox的任何内容时,其空白或为空。

我也尝试了这两种方法,但其中没有一种方法有效。 (我在命令运行后将过程传递给他们。)

当你点击方法的按钮时,这两个都会导致应用程序冻结。

String termReader(Process process){
    BufferedReader reader = new BufferedReader(
        new InputStreamReader(process.getInputStream()));   
    try {

    int i;
    char[] buffer = new char[4096];
    StringBuffer output = new StringBuffer();
    while ((i = reader.read(buffer)) > 0) output.append(buffer, 0, i);
    reader.close();
    return output.toString();
    } catch (IOException e) {
    e.printStackTrace();
    return e.getMessage();
    }
}



String processReader(Process process){
    InputStream stdout = process.getInputStream();
    byte[] buffer = new byte[1024];
    int read;
    String out = new String();
    while(true){
        try {
            read = stdout.read(buffer);
        out += new String(buffer, 0, read);
        if(read<1024){
            break;
        }
        } catch (IOException e) {
            e.printStackTrace();

        }
    }
    return out;
}

Theres没有堆栈跟踪可以使用,所以我开始有点难过。

使用下面提出的代码编辑,嗯,下面:D 我稍微改变了它,使其成为一个单击运行的东西,以便于故障排除和测试。

当它尝试读取输入流时也会冻结,如果我在尝试读取流之前调用stdin.writeBytes(“exit \ n”),它会在关闭终端时给出空白答案,如果我在之后调用它,它无休止地循环。

        void Run() {
                String command = "busybox traceroute\n";



        StringBuffer theRun = null;
        try {
            Process process = Runtime.getRuntime().exec("su");
            DataOutputStream stdin = new DataOutputStream(process.getOutputStream());
            stdin.writeBytes(command);
            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()));
            int read;
            char[] buffer = new char[4096];
            StringBuffer output = new StringBuffer();
            while ((read = reader.read(buffer)) > 0) {
                theRun = output.append(buffer, 0, read);
            }
            reader.close();
            process.waitFor();

        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        Toast.makeText(getApplicationContext(), theRun, Toast.LENGTH_SHORT).show();
    }

它似乎跳过第一行(每次调用命令时获得的busybox信息行)并且没有捕获其余数据。我已经尝试了所有我能想到的变化来使这个工作正常:/

如果有人对此有所了解,我会非常谨慎:)

2 个答案:

答案 0 :(得分:3)

这是一个快速解决方案......这是我为此创建的实用程序类。您可以使用本机shell,如果设备已植根,则使用root shell,或者设置自定义shell。你走了。

https://github.com/jjNford/android-shell

答案 1 :(得分:1)

我找到了一种解决方法。

首先,在我的情况下运行链接到busybox的命令永远不会通过它的InputStream返回它的输出,无论我尝试了什么方法(我试过ALOT大声笑)。

这是我发现我能做到的。它有点乏味,并没有给你完整的输出,但如果你想要的东西依赖于命令是否正常发射(在我的情况下,如果我不能比较一切运行的话,我的应用程序就不会正常工作。)

你无法从流程中获得输入,但如果你正确工作,你可以获得退出值:)这适用于任何不会给你复杂响应的东西(比如在大文件上使用cat)

两者之间的差异很容易找到,例如:

command = "cat /sys" // works, exits with 1

command = "cat /init.rc"  doesnt work, exits with 0

这就是我如何设置它以便轻松工作。使用MasterJB提供的方法正常运行命令:

            Process p;
        try {
            p = Runtime.getRuntime().exec(new String[]{"su", "-c", "/system/bin/sh"});
        DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
        stdin.writeBytes(command); 
        stdin.writeBytes("echo $?\n"); 

        DataInputStream stdout = new DataInputStream(p.getInputStream());
        byte[] buffer = new byte[4096];
        int read = 0;
        String out = new String();
        while(true){
            read = stdout.read(buffer);
            out += new String(buffer, 0, read);
            if(read<4096){
                break;
            }

                    // here is where you catch the error value

                                int len = out.length();
        char suExitValue = out.charAt(len-2);
        Toast.makeText(getApplicationContext(), String.valueOf(suExitValue), Toast.LENGTH_SHORT).show();


                    return0or1(Integer.valueOf(suExitValue), command); // 0 or 1 Method

                    // end catching exit value                            

        }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

我还发现更容易制作一个“0或1”方法来返回发生的事情。在这个例子中它被解雇为吐司。你可能还想测试char是否是一个整数,因为有些命令没有给出任何退出值(很奇怪,我知道。一个实例是ls / sys,当通过su终端运行时返回一个空白的退出值。 )

    String return0or1 (int returnValue, String command){
    String message = command + " - Cannot get return value.";

    if (returnValue == 0){
        message = command + " - successful.";
        return message;
    }
    if (returnValue == 1){
        message = command + " - failed.";
        return message;
    }
    return message;
}

通过一些研究,您可以将任何退出值与正确的响应相匹配,只需将它们捕获正确:)

这些方法只返回命令是否为run(0),但是如果它获得double或triple char退出代码,则当它失败时(即当退出值为10时),最后一位数字可能为0,因此这将起作用大多数情况下,但需要扩大以获得双重和三重值。