2012-12-10 105 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掛起之前抓住最後一行,等待下一個線進來。 –

相關問題