【问题标题】:Performing multiple executions on Runtime exec在 Runtime exec 上执行多次执行
【发布时间】:2013-03-19 21:55:36
【问题描述】:

我正在尝试在 Android 中做这个简单的 unix ls:

cd /data

然后

ls

它应该返回 /data 文件夹的所有内容。

我已经编码了:

try {
       String line;
       Process p = Runtime.getRuntime().exec(new String[] { "ls /data"});
       BufferedReader in = new BufferedReader(
               new InputStreamReader(p.getInputStream()) );
       while ((line = in.readLine()) != null) {
         Log.d("debugging", line);
       }
       in.close();
     }
     catch (Exception e) {
       e.printStackTrace();
     }

我目前面临的问题是,我一次只能执行一个命令。例如,如果我写 ls /data 它什么也不返回。看来他不喜欢空格。

如果我只写一个像“ls”这样返回根目录列表的单词,一切都会正常工作:

03-19 22:51:59.241: D/debugging(16274): acct
03-19 22:51:59.241: D/debugging(16274): cache
03-19 22:51:59.241: D/debugging(16274): config
03-19 22:51:59.241: D/debugging(16274): crashtag
03-19 22:51:59.241: D/debugging(16274): d
03-19 22:51:59.241: D/debugging(16274): data
03-19 22:51:59.241: D/debugging(16274): default.prop
03-19 22:51:59.241: D/debugging(16274): dev
03-19 22:51:59.241: D/debugging(16274): etc
03-19 22:51:59.241: D/debugging(16274): fstab
03-19 22:51:59.241: D/debugging(16274): init
03-19 22:51:59.241: D/debugging(16274): init.clrdex.sh
03-19 22:51:59.241: D/debugging(16274): init.goldfish.rc
03-19 22:51:59.241: D/debugging(16274): init.hostapd.sh
03-19 22:51:59.241: D/debugging(16274): init.rc
03-19 22:51:59.241: D/debugging(16274): init.semc.rc
03-19 22:51:59.241: D/debugging(16274): init.usbmode.sh
03-19 22:51:59.241: D/debugging(16274): logo.rle
03-19 22:51:59.241: D/debugging(16274): mnt
03-19 22:51:59.241: D/debugging(16274): mr.log
03-19 22:51:59.241: D/debugging(16274): proc
03-19 22:51:59.241: D/debugging(16274): root
03-19 22:51:59.241: D/debugging(16274): sbin
03-19 22:51:59.241: D/debugging(16274): sdcard
03-19 22:51:59.241: D/debugging(16274): sys
03-19 22:51:59.241: D/debugging(16274): system
03-19 22:51:59.241: D/debugging(16274): ueventd.goldfish.rc
03-19 22:51:59.241: D/debugging(16274): ueventd.rc
03-19 22:51:59.241: D/debugging(16274): ueventd.semc.rc
03-19 22:51:59.241: D/debugging(16274): vendor

正如有人提到的那样,我已经尝试用多个命令填充该数组,但它什么也没返回。空白。

{"ls","ls"} //this should return twice ls result.

任何想法如何在 Android 运行时“连接”命令?

【问题讨论】:

  • 你真的需要 System.exec 吗?您是否考虑过使用 File (docs.oracle.com/javase/6/docs/api/java/io/File.html) 中的 listFiles() 方法
  • 我会使用ProcessBuilder 而不是Runtime.getRuntime.exec()
  • 我愿意,因为这不是我最终想要做的。我想调用一个系统程序,但如果我不能同时处理两个不同的命令,我将无法运行这些程序
  • @SergiCastellsaguéMillán 也许您可以使用所需的命令制作.sh 脚本文件并使用 java 运行该文件。我认为它与 Windows 中 .bat 文件的概念相同。 ---> execute .bat file from android

标签: java android runtime.exec


【解决方案1】:

我认为你需要root权限才能执行ls /data命令所以你应该先获取su shell然后执行命令,例如:

// run command with su rights and return output of that command(inside su
// shell)
// command = "ls /data"
public static void suOutputExecute(String command) {
    try {
        int BUFF_LEN = 1024;
        Process p = Runtime.getRuntime().exec(new String[] { "su", "-c", "system/bin/sh" });
        DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
        // from here all commands are executed with su permissions
        stdin.writeBytes(command + "\n"); // \n executes the command
        InputStream stdout = p.getInputStream();
        byte[] buffer = new byte[BUFF_LEN];
        int read;
        String out = new String();
        // while((read=stdout.read(buffer))>0) won't work here
        while (true) {
            read = stdout.read(buffer);
            out += new String(buffer, 0, read);
            if (read < BUFF_LEN) {
                // we have read everything
                break;
            }
        }
        stdout.close();
        Log.e("ROOT", out);
        p.waitFor();
    } catch (Exception e) {
        Log.e("ROOT", "Error", e);
    }
}

您需要有根设备。对于模拟器,您仍然需要安装超级用户。

对于不需要 su 的命令,下面的代码应该可以工作(我现在无法测试它):

public static void shExecute(String[] commands) {
    Process shell = null;
    DataOutputStream out = null;
    BufferedReader in = null;

    try {
        // Acquire sh
        Log.i(LOG_TAG, "Starting exec of sh");
        shell = Runtime.getRuntime().exec("sh");//su if needed
        out = new DataOutputStream(shell.getOutputStream());

        in = new BufferedReader(new InputStreamReader(shell.getInputStream()));

        // Executing commands without root rights
        Log.i(LOG_TAG, "Executing commands...");
        for (String command : commands) {
            Log.i(LOG_TAG, "Executing: " + command);
            out.writeBytes(command + "\n");
            out.flush();
        }

        out.writeBytes("exit\n");
        out.flush();
        String line;
        StringBuilder sb = new StringBuilder();
        while ((line = in.readLine()) != null) {
            sb.append(line).append("\n");
        }
        Log.i(LOG_TAG, sb.toString());
        shell.waitFor();

    } catch (Exception e) {
        Log.e(LOG_TAG, "ShellRoot#shExecute() finished with error", e);
    } finally {
        try {
            if (out != null) {
                out.close();
            }
            if(in != null){
                in.close();
            }
            // shell.destroy();
        } catch (Exception e) {
            // hopeless
        }
    }
}

【讨论】:

  • 使用此代码我可以“读取”命令生成的输出吗?
  • 是的,至少对于第一个例子,我不太确定第二个例子。
【解决方案2】:

我认为你的问题出在

Process p = Runtime.getRuntime().exec(new String[] { "ls /data"});

您应该使用 exec(String command) 或将“ls /data”分成两个字符串

Runtime.getRuntime().exec(new String[] { "ls", "/data"});

【讨论】:

  • Runtime.getRuntime().exec(new String[] { "ls", "/data"}); 显然没有返回任何数据。
  • 它是否抛出异常?
  • 没什么。 catch (Exception e) { Log.d("debugging","Exception"); e.printStackTrace(); } 没有打印。
  • 如果你输入一个明显伪造的命令而不是“ls”,你会得到任何错误吗?如果由于任何原因无法执行命令,它应该抛出 IOException。
  • 不,我也是这样。如果我输入“dsadasofpasnfas”,它也不会返回任何内容。也许是因为BufferedReader in = new BufferedReader( new InputStreamReader(p.getInputStream()) ); 只听标准输出而不是标准错误?我不确定...
【解决方案3】:

您是否为 java 运行时探索过这个 exec 命令,使用您想要“cd”到的路径创建一个文件对象,然后将其作为 exec 方法的第三个参数输入。

public Process exec(String command,
                String[] envp,
                File dir)
         throws IOException

在具有指定环境和工作目录的单独进程中执行指定的字符串命令。

这是一种方便的方法。 exec(command, envp, dir) 形式的调用与 exec(cmdarray, envp, dir) 调用的行为方式完全相同,其中 cmdarray 是命令中所有标记的数组。

更准确地说,命令字符串使用由调用 new StringTokenizer(command) 创建的 StringTokenizer 分解为标记,而无需进一步修改字符类别。然后将分词器生成的令牌以相同的顺序放置在新的字符串数组 cmdarray 中。

Parameters:
    command - a specified system command.
    envp - array of strings, each element of which has environment variable settings in the format name=value, or null if the subprocess should inherit the environment of the current process.
    dir - the working directory of the subprocess, or null if the subprocess should inherit the working directory of the current process. 
Returns:
    A new Process object for managing the subprocess 
Throws:
    SecurityException - If a security manager exists and its checkExec method doesn't allow creation of the subprocess 
    IOException - If an I/O error occurs 
    NullPointerException - If command is null, or one of the elements of envp is null 
    IllegalArgumentException - If command is empty

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-17
    相关资源
    最近更新 更多