Runtime.getRuntime exec

时间:2012-12-10 18:10:47

标签: java android

我已经创建了一个类来处理Android应用程序中的root命令,它主要工作得很好。我使用Runtime.getRuntime()。exec(" su")创建进程,然后使用DataOutputStream输入命令,并使用DataInputStream和不推荐使用的readLine从命令中获取数据。 (我尝试过使用BufferedReader,但问题没有区别。)

我的问题是,如果命令产生错误,应用程序将挂起。 F.eks。如果我执行命令" [-f / test]&& md5sum / test" ||回声0"我没有问题。但是,如果我执行" md5sum / test"并且文件不存在,我将不得不强制关闭应用程序,因为它将无处可去。在这个例子中,解决方案只是为了检查文件,就像在第一个例子中一样,但不是每种情况都这么简单。问题可能发生,当他们这样做时,人们不应该强制关闭应用程序。

有没有办法解决这个问题?

2 个答案:

答案 0 :(得分:2)

您的应用可能会挂起,因为您可能没有处理由生成的进程生成的stderr / stdout。这背后的原因是产生的进程具有非常小的输出缓冲区(通常只有几千字节)。一旦这些缓冲区已满,该进程将挂起,直到其缓冲区释放足够的空间,以便继续写入输出文本。我怀疑你在运行第二个命令时遇到问题,因为第二个命令失败并产生大量控制台输出。您的子进程耗尽缓冲区空间,然后尝试阻塞,直到有更多空间可用,这种情况永远不会发生。

Runtime.getRuntime().exec()返回Process的实例。 Process个对象有一个访问器方法(我相信它是getInputStream()),允许你使用它的标准输出。您还需要对getErrorStream()执行相同的操作。通常,我得到InputStream,然后让一个单独的线程继续使用InputStream中的数据,直到它关闭为止。您不需要对数据本身做任何事情,只需阅读即可。这将告诉基础进程它可以清除其输出缓冲区,希望它们在它们变满之前(从而导致进程阻塞)。

另外,我并不是100%熟悉Android,但在普通的'java中,最好使用ProcessBuilder来生成子Process个实例。这是因为ProcessBuilder允许您在同一个流中组合子节点的stderr和stdout,这样您只需从process.getInputStream()返回的流中读取数据就可以在单个线程中使用它们。

答案 1 :(得分:0)

好的,我已经看过ProcessBuilder(也适用于android)。但我仍遇到问题。

while ((line = buffer.readLine()) != null) {
    data = line;
}

if (data != null && data.contains("uid=0")) {
    return true;
}

这将提供与以前相同的问题。它无处可去。但是,如果我将代码更改为

while ((line = buffer.readLine()) != null) {
    if (data != null && data.contains("uid=0")) {
        return true;
    }
}

这样可以正常工作。这个过程将结束,它将返回真实。问题是,为了让我使用它,我必须知道什么是期望作为返回数据(我在这个测试方法中做)。所以这不是解决方案。

以下是整个测试方法

try {
    ProcessBuilder builder = new ProcessBuilder("su");
    builder.redirectErrorStream(true);

    Process process = builder.start();
    DataOutputStream output = new DataOutputStream(process.getOutputStream());
    InputStreamReader reader = new InputStreamReader(process.getInputStream());
    BufferedReader buffer = new BufferedReader(reader);

    output.writeBytes("id\n");
    output.flush();

    String line = null;
    String data = null;
    while ((line = buffer.readLine()) != null) {
        data = line;
    }

    if (data != null && data.contains("uid=0")) {
        return true;
    }

} catch(Throwable e) {
    Log.d(TAG, "Root access rejected [" + e.getClass().getName() + "] : " + e.getMessage());
}

return false;