簡體   English   中英

Android Java Runtime.exec(“su”) 掛起(設備問題?在其他設備上工作正常)

[英]Android Java Runtime.exec(“su”) hangs (Device Problem? works fine on other devices)

我在我的 android 應用程序上運行 tcpdump 命令,這需要 root 權限。 突然之間,“su”命令后跟一系列命令(任何命令不僅是示例)導致進程掛起(process.waitFor() 永遠等待)。 它工作正常,而且問題出在哪里,我嘗試回滾到以前工作的版本並且問題仍然存在。

我正在使用 Redmi Note 4X 規格:Android 版本:6.0 MRA58K | MIUI 版本:MIUI Global 10.2.1.0(不知道還需要什么)

我嘗試在沒有 root 的情況下運行它並讀取錯誤 stream 工作正常它會產生一個錯誤,說我沒有權限(它假設)。 我曾嘗試手動殺死一些進程,認為可能有一些僵屍進程阻塞了新進程 stream,但我不知道是什么問題。 我試過用谷歌搜索答案,但它們主要是指獲取 output。 我已經嘗試過 adb shell 中的命令,它工作得很好。

java
        BufferedReader in = null;
        Process process = null;
        try {
            process = Runtime.getRuntime().exec("su");
            DataOutputStream cmd = new DataOutputStream(process.getOutputStream());
            cmd.writeBytes("tcpdump --version\n");
            cmd.flush();
            cmd.writeBytes("exit\n");
            cmd.flush();
            in = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            String line = null;
            process.waitFor();
            if(in.ready()){
                line = in.readLine();
            }

            if(line != null){
                Log.d(TAG, line);
            }else{
                Log.d(TAG, "NO OUTPUT!");
            }

            in.close();
        } catch (IOException e) {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException ex) {
                }
            }
        } catch (InterruptedException e) {
            if(in != null){
                try{
                    in.close();
                } catch (IOException ex) { }
            }
        }finally {
            if(process != null){
                process.destroy();
            }
        }

我希望進程結束,但線程卡在 process.waitFor() 上。

更新 1.0 我已經按照建議實現了 ProcessBuilder。 但是,日志中沒有 output 並且主線程仍然掛起(p.waitFor() 永遠等待)。 正如我已經說過的,“su”命令不會在我正在測試的環境中請求任何密碼。 它正在使用 Droid4X 模擬器。

private void updateSpinner(){

        BufferedReader in = null;
        Process p = null;
        try {
            ProcessBuilder processBuilder = new ProcessBuilder("su", "tcpdump", "--version");
            processBuilder.redirectErrorStream(true);
            p = processBuilder.start();
            in = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                Log.d(TAG, line);
            }
            in.close();
            int exitCode = p.waitFor();
        } catch (IOException e) {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException ex) {
                }
            }
        } catch (InterruptedException e) {
            if(in != null){
                try{
                    in.close();
                } catch (IOException ex) { }
            }
        }finally {
            if(p != null){
                p.destroy();
            }
        }

您可能使用了錯誤的命令。 su命令說明如下:

su命令用於在登錄 session 期間成為另一個用戶。”

但是您在這里擁有的不是登錄session。

“如果合適,將提示用戶輸入密碼。”

在您的情況下,由於您嘗試suroot ,因此su命令將提示輸入root密碼。 您的 Java 代碼未發送密碼。 這可能就是為什么su掛了!


所以讓我們退后一步。

使用su執行此操作是個壞主意。 您的 Java 應用程序將需要“知道”根密碼。 這意味着它必須存儲在程序可以獲取它的地方。 由於該程序此時將是無特權的,這會帶來很大的安全問題。

一個更好的主意是使用sudo sudo命令將單個命令作為特權命令執行; 例如sudo ls -l ls -l 通常,它會提示輸入密碼,但是:

  • 可以配置sudo以使某些用戶或命令組不受此限制,並且

  • 您可以將密碼作為命令行選項傳遞給sudo

也可以配置sudo使某些用戶只能以root身份執行某些命令。 閱讀man sudoman sudoers了解詳細信息。


因此,如果您要使用來自 Java 的sudo tcpdump --version (並且您已經處理了密碼和權限控制問題),您只需要執行以下操作:

Process p = new ProcessBuilder("sudo", "tcpdump", "--version").start();
Reader in = new InputStreamReader(p.getInputStream());
// read the version string from the processes stdout
in.close();
int exitCode = p.waitFor();

請注意, ProcessBuilder允許您做更多的事情; 請參閱javadoc

如果您需要運行多個命令,請考慮編寫 shell 腳本來執行它們,然后sudo腳本。 (但要警惕有人可以通過環境變量改變 shell 腳本的行為的各種詭計。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM