如何使用“su”在运行时发送命令,并从DataInputStream返回所有行

时间:2013-01-10 20:51:27

标签: android datainputstream

我正在开发一个程序,需要能够确定Xlocation上Android设备上的内容。我正在使用“su ls Xlocation”

我想找回文件的数组列表,但只能设法取回第一个项目。我错过了获得下一行的命令吗?或者还有其他我需要做的事情。

以下是我发送的命令

String[] commands = new String[]{"ls /system/app/"};
return doCommand(commands);

以下是我当前的doCommand方法

    private boolean doCommand(String[] commands)
    {
    ArrayList<String> output = new ArrayList<String>();

    boolean ran = false;
    try
    {
        Process process = Runtime.getRuntime().exec("su");
        DataOutputStream os = new DataOutputStream(process.getOutputStream());
        DataInputStream ins = new DataInputStream(process.getInputStream());

        // This part works I sends the command right!
        for (String single : commands) 
        {
            os.writeBytes(single + "\n");
            os.flush();
            os.writeBytes("exit\n");
            os.flush();
            process.waitFor();
            ran = true;
        }

        int av = -1;
        while (av != 0)
        {

//////////////////////////// WORKING ON THIS TO GET ALL INFO /////////////////
            av = ins.available();
            if (av != 0) 
            {
                byte[] b = new byte[av];
                ins.read(b);
                output.add(new String(b));
                System.out.println(new String(b) + "Recieved form modem");
            }
        }
    }
    catch(Exception ex){}
    return ran;
}

如目前所见,它只返回true或false。但是在调试中运行我只得到输出中的第一项。 (output =“[first.apk”)

编辑较新的版本;

    public ArrayList<String> doCommand(String[] commands)
{

    ArrayList<String> output = new ArrayList<String>();

    try
    {

        Process process = Runtime.getRuntime().exec("su");
        DataOutputStream os = new DataOutputStream(process.getOutputStream());  
        DataInputStream ins = new DataInputStream(process.getInputStream());
        for (String single : commands) 
        {
            os.writeBytes(single + "\n");

            //os.flush();
            output.add("true");
        }
        os.writeBytes("exit\n");


        byte[] bc = new byte[10000];
        String st = "";
        while(ins.read(bc) != -1)
        {
        st += new String(bc);
        os.flush();

        }
        output.add(st);


        os.flush();
        os.close();
        ins.close();
        process.waitFor();          
    }
    catch(Exception ex)
    {}

    return output;
}

现在获得了相当数量的输出,但仍然不是所有目录都有大量项目的大小限制在字节[10000]我检查过。

如果有人想要对此进行改进并获得有效的确切答案,我仍然会查看此帖子。

由于

2 个答案:

答案 0 :(得分:2)

您可以尝试从我的开源用户管理(GitHub)应用中调整此方法,以执行您想要的操作。这将按照终端命令读取输出的每一行:

public static String[] getUserList()
{
    Process p;
    try {
        p = Runtime.getRuntime().exec("su");
        DataOutputStream os = new DataOutputStream(p.getOutputStream());  
        BufferedReader bf = new BufferedReader(new InputStreamReader(p.getInputStream()));

            os.writeBytes("pm list-users"+"\n");
            os.writeBytes("exit\n"); 
            ArrayList<String> users = new ArrayList<String>();
            String test;
            bf.readLine();
            while((test = bf.readLine()) != null)
            {
                users.add(test);
            }

            String[] userList = (String[]) users.toArray(new String[users.size()]);



        os.flush();
        return userList;
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
}

答案 1 :(得分:2)

我对Java有点新意,但我认为这个问题只是一个小小的疏忽......我用Python遇到过几次;)

因为您已将以下内容添加到while循环中:

        os.writeBytes("exit\n");
        os.flush();

每次迭代后,您都试图退出终端会话。在第一次迭代之后,终端会话已经关闭,因此这将解释为什么只返回第一个结果。

我建议在while循环完成后添加退出代码,以确保您不会将其余命令发送到死会话。或者,您也可以在每次迭代期间重新创建操作系统,但这似乎有点多余。 ;)

编辑#1

我不熟悉字节的用法,但我能够用类似的while循环解析命令的输出。我还在输入中添加了stderr,以确保在需要时清空缓冲区。在第一眼看到您的新代码时,您似乎在while循环的每次迭代期间定义了一个新的String,而不是将该行附加到变量。这会导致在每次迭代期间覆盖您的变量。 ;)

以下是我过去用来完成类似任务的一些代码。我很快就从我的源代码进行了修改,但我目前无法进行测试运行。请记住您的 os 是我的 stdout ,你的 ins 是我的 stdin

Runtime          terminal = (Runtime) Runtime.getRuntime();
Process          process  = terminal.exec("su");
DataOutputStream stdout   = new DataOutputStream(process.getOutputStream());
InputStream      stderr   = process.getErrorStream();
BufferedReader   stdin    = new BufferedReader(new InputStreamReader(stderr));
String           line     = "";
String           output   = "";

// Execute command and flush 
stdout.writeBytes("your command here\n");
stdout.flush();

// Append stdin.readLine() to output variable until line is null
while ((line = stdin.readLine()) != null)
    output += line;

// I've had mixed luck getting waitFor() to work, but technically it should force
// the shell to wait until the command completes. Uncomment it to try it out.
//process.waitFor();
stdout.writeBytes("exit\n");
stdout.flush();

// Print output to logcat
System.out.println(output);