2012-12-10 107 views
1

我已经创建了一个类来处理android应用程序中的根命令,它主要工作得很好。我使用Runtime.getRuntime()。exec(“su”)创建过程,然后使用DataOutputStream输入命令,并使用DataInputStream和不建议使用的readLine从命令中获取数据。 (我曾尝试使用BufferedReader代替,但没有问题)。Runtime.getRuntime exec

我的问题是,如果命令产生错误,应用程序将挂起。 F.eks。如果我执行命令“[-f/test] & & md5sum/test”|| echo 0“我将没有任何问题,但是,如果我执行”md5sum/test“并且文件不存在,我将不得不强制关闭应用程序,因为它将无处可用。检查像在第一个例子中的文件,但不是每一种情况是这么简单。问题可能发生,而在这个时候,人们不应该强行关闭应用程序。

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

+0

什么你试试? –

+1

你可能没有完全正确地读取它的stdout/stderr流 –

+0

好的,你能否提供一个如何正确的读取它的例子? –

回答

2

你的应用程序很可能是挂起的,因为你可能没有处理派生进程产生的stderr/stdout,其原因是产生的进程有非常小的输出缓冲区(通常只有几千字节)这个过程会一直持续下去,直到它的缓冲区释放出足够的空间让它继续写入输出文本。我怀疑在运行第二条命令时遇到问题,因为第二条命令失败并生成大量控制台输出。您的子进程耗尽了缓冲区空间,然后尝试阻塞,直到有更多空间可用,这种情况从未发生过。

Runtime.getRuntime().exec()返回Process的实例。 Process对象有一个访问器方法(我相信它是getInputStream()),它允许你使用它的标准输出。您还需要与getErrorStream()一样。通常情况下,我得到InputStream,然后有一个单独的线程不断从该InputStream消耗数据,直到它关闭。您不需要对数据本身做任何事情,只需阅读它即可。这将告诉底层进程它可以清除它的输出缓冲区,希望在它们变满之前(因此导致进程阻塞)。

此外,我不是100%熟悉Android,但在普通的ol'java中,最好使用ProcessBuilder来生成子实例Process。这是因为ProcessBuilder可让您将孩子的stderr与stdout组合到同一个流中,这样您就可以通过从process.getInputStream()返回的流中读取数据,从而在单个线程内使用这两者。

+0

谢谢。这很有道理。我会玩这个,也看看ProcessBuilder。再次感谢:) –

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; 
+1

好吧,我做了一个解决方案,接缝工作正常。在output.writeBytes(cmd +“\ n”)之后,在output.flush()之前添加output.writeBytes(“echo EOL:a00c38d8:EOL \ n”)。然后在循环中,你可以做(​​(line = buffer.readLine())!= null &&!“EOL:a00c38d8:EOL”.equals(line))并且在readLine挂起之前抓住最后一行,等待下一个线进来。 –

相关问题