我已经创建了一个类来处理Android应用程序中的root命令,它主要工作得很好。我使用Runtime.getRuntime()。exec(" su")创建进程,然后使用DataOutputStream输入命令,并使用DataInputStream和不推荐使用的readLine从命令中获取数据。 (我尝试过使用BufferedReader,但问题没有区别。)
我的问题是,如果命令产生错误,应用程序将挂起。 F.eks。如果我执行命令" [-f / test]&& md5sum / test" ||回声0"我没有问题。但是,如果我执行" md5sum / test"并且文件不存在,我将不得不强制关闭应用程序,因为它将无处可去。在这个例子中,解决方案只是为了检查文件,就像在第一个例子中一样,但不是每种情况都这么简单。问题可能发生,当他们这样做时,人们不应该强制关闭应用程序。
有没有办法解决这个问题?
答案 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;