6

私の人生では、アプリが su シェル内から busybox を呼び出すプロセスからの応答を取得することはできません。

3つの異なる方法を試し、3つの方法を組み合わせて動作させようとしましたが、busyboxを使用して何かから出力を取得することはできず、残りのコマンドのみを取得しました.

より具体的には、ls /dataやのようなコマンドを返すようにできますcat suchandsuch.fileが、「busybox」で始まるもの (つまり、busybox マウント、busybox フリー) は何も表示されません。

これは私に最も近い方法でした。このコードは で動作しますls /dataが、「busybox free」では動作しません

これはコマンドを実行し (ほとんどの場合)、入力ストリームから無限にループする代わりに空の文字列を返します。

Process p;
try {
    p = Runtime.getRuntime().exec(new String[]{"su", "-c", "/system/bin/sh"});
    DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
    stdin.writeBytes("ls /data\n");
    DataInputStream stdout = new DataInputStream(p.getInputStream());
    byte[] buffer = new byte[4096];
    int read = 0;
    String out = new String();

    while(true){
        read = stdout.read(buffer);
        out += new String(buffer, 0, read);
        if(read<4096){
            break;
    }
}
    Toast.makeText(getApplicationContext(), out, Toast.LENGTH_SHORT).show();
} catch (IOException e) {
    e.printStackTrace();
}

下部近くのトーストには からすべてが表示ls /dataされますが、busybox の何かに変更されると、空白または null になります。

私もこれらの両方を試しましたが、どちらも機能しませんでした。(コマンドの実行後にプロセスを渡していました。)

これらはどちらも、メソッドのボタンを押すと、常にアプリがフリーズする結果になります。

String termReader(Process process){
    BufferedReader reader = new BufferedReader(
        new InputStreamReader(process.getInputStream()));   
    try {
        int i;
        char[] buffer = new char[4096];
        StringBuffer output = new StringBuffer();

        while ((i = reader.read(buffer)) > 0) 
            output.append(buffer, 0, i);

        reader.close();
        return output.toString();
    } catch (IOException e) {
        e.printStackTrace();
        return e.getMessage();
    }
}


String processReader(Process process){
    InputStream stdout = process.getInputStream();
    byte[] buffer = new byte[1024];
    int read;
    String out = new String();
    while(true){
        try {
            read = stdout.read(buffer);
            out += new String(buffer, 0, read);
            if(read<1024){
            break;
        }
        } catch (IOException e) {
            e.printStackTrace();                            
        }
    }
    return out;
}

作業するスタック トレースがないため、少し困惑し始めています。

以下に提案されたコードで編集されました.

これは、入力ストリームを読み込もうとするとフリーズしstdin.writeBytes("exit\n")ます。ストリームを読み込もうとする前に呼び出すと、端末を閉じることから空白の答えが返されます。後で呼び出すと、無限にループします。

void Run() {
    String command = "busybox traceroute\n";

    StringBuffer theRun = null;
    try {
        Process process = Runtime.getRuntime().exec("su");
        DataOutputStream stdin = new DataOutputStream(process.getOutputStream());
        stdin.writeBytes(command);
        BufferedReader reader = new BufferedReader(
        new InputStreamReader(process.getInputStream()));
        int read;
        char[] buffer = new char[4096];
        StringBuffer output = new StringBuffer();

        while ((read = reader.read(buffer)) > 0) {
            theRun = output.append(buffer, 0, read);
    }

    reader.close();
    process.waitFor();

    } catch (IOException e) {
        throw new RuntimeException(e);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    Toast.makeText(getApplicationContext(), theRun, Toast.LENGTH_SHORT).show();
}

最初の行 (コマンドを呼び出すたびに取得する busybox 情報行) をスキップし、残りのデータをキャッチしていないようです。これを正しく機能させるために、考えられるすべてのバリエーションを試しました:/

誰かがこれについて洞察を持っているなら、私は大いに感謝しています:)

4

2 に答える 2

3

これが簡単な解決策です...これは、このためだけに作成したユーティリティクラスです。ネイティブ シェル、デバイスがルート化されている場合はルート シェルを使用するか、カスタム シェルを設定できます。どうぞ。

https://github.com/jjNford/android-shell

于 2012-04-10T19:15:53.953 に答える
1

これに対する一種の回避策を見つけました。

まず第一に、私の場合、busybox にリンクされたコマンドを実行すると、どの方法を試しても、InputStream を介して出力が返されることはありません (そして、ALOT を試しました笑)。

これが私ができることがわかったことです。これは少し面倒で、完全な出力が得られるわけではありませんが、コマンドが適切に実行されたかどうかを確認したい場合 (私の場合、すべてを比較できなければ、私のアプリは正しく動作しません)走った。)

プロセスから入力を取得することはできませんが、正しく処理すれば終了値を取得できます:)これは、複雑な応答を返さないもの(大きなファイルで cat を使用するなど)で機能します

この 2 つの違いは、次のように簡単に見つけることができます。

command = "cat /sys" // works, exits with 1

command = "cat /init.rc"  doesnt work, exits with 0

これで、簡単に動作するように設定できました。MasterJB が提供する方法を使用して、通常どおりコマンドを実行します。

process p;
try {
    p = Runtime.getRuntime().exec(new String[]{"su", "-c", "/system/bin/sh"});
    DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
    stdin.writeBytes(command); 
    stdin.writeBytes("echo $?\n"); 

    DataInputStream stdout = new DataInputStream(p.getInputStream());
    byte[] buffer = new byte[4096];
    int read = 0;
    String out = new String();

    while(true){
        read = stdout.read(buffer);
        out += new String(buffer, 0, read);
        if(read<4096){
            break;
        }
    // here is where you catch the error value

    int len = out.length();
    char suExitValue = out.charAt(len-2);
    Toast.makeText(getApplicationContext(), String.valueOf(suExitValue), Toast.LENGTH_SHORT).show();

    return0or1(Integer.valueOf(suExitValue), command); // 0 or 1 Method
    // end catching exit value                            
}
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

また、何が起こったかを返す「0 または 1」メソッドを作成する方が簡単であることもわかりました。この例では、トーストとして起動されます。一部のコマンドは終了値をまったく与えないため、char が実際に整数であるかどうかをテストすることもできます (奇妙なことに、1 つのインスタンスは ls /sys であり、su ターミナルを介して実行すると空白の終了値が返されます)。

String return0or1 (int returnValue, String command){
String message = command + " - Cannot get return value.";

if (returnValue == 0){
    message = command + " - successful.";
    return message;
}
if (returnValue == 1){
    message = command + " - failed.";
    return message;
}
return message;
}

少しの調査で、ほぼすべての終了値を適切な応答と一致させることができます。それらを正しくキャプチャする必要があります:)

これらのメソッドは、コマンドが実行されたかどうか (0) を返しますが、2 文字または 3 文字の終了コードを取得した場合、失敗したとき (つまり、終了値が 10 のとき) の最後の桁が 0 になる可能性があるため、ほとんどの場合、これは機能します。ただし、double および triple 値をキャッチするには拡張する必要があります。

于 2012-04-09T19:02:29.320 に答える