1

Androidアプリでルートコマンドを処理するクラスを作成しましたが、ほとんど問題なく動作しています。Runtime.getRuntime().exec("su") でプロセスを作成し、DataOutputStream を使用してコマンドを入力し、DataInputStream と非推奨の readLine を使用してコマンドからデータを取得します。(代わりに BufferedReader を使用してみましたが、問題に違いはありません)。

私の問題は、コマンドでエラーが発生するとアプリがハングすることです。F.eks。コマンド "[ -f /test ] && md5sum /test" || を実行すると、echo 0" 問題はありません。ただし、"md5sum /test" を実行してもファイルが存在しない場合は、アプリを強制終了する必要があります。この例では、解決策は次のとおりです。最初の例のようにファイルをチェックしますが、すべての状況がこのように単純であるとは限りません. 問題が発生する可能性があり、問題が発生した場合、人々はアプリケーションを強制的に閉じる必要はありません.

この問題を解決する方法はありますか?

4

2 に答える 2

3

生成されたプロセスによって生成された stderr/stdout を処理していない可能性があるため、アプリがハングしている可能性があります。これは、生成されたプロセスの出力バッファが非常に小さい (通常は数キロバイト) ためです。これらのバッファーがいっぱいになると、出力テキストの書き込みを続行するのに十分なスペースがバッファーに解放されるまで、そのプロセスはハングします。2 番目のコマンドが失敗し、大量のコンソール出力が生成されるため、2 番目のコマンドの実行時に問題が発生していると思われます。子プロセスはバッファ領域を使い果たし、より多くの領域が利用可能になるまでブロックしようとしますが、これは決して起こりません。

Runtime.getRuntime().exec()のインスタンスを返しますProcess。 オブジェクトには、そのstdoutを使用できるようにProcessするアクセサメソッド(私はそれだと思います)があります。getInputStream()で同じことを行う必要もありますgetErrorStream()。通常、私は を取得しInputStream、別のスレッドがInputStream閉じられるまで、それからデータを継続的に消費します。データ自体で何もする必要はありません。データを読み取るだけです。これにより、出力バッファーがいっぱいになる前に、出力バッファーをクリアできることが下層のプロセスに通知されます (したがって、プロセスがブロックされます)。

また、私は Android に 100% 精通しているわけではありませんが、普通の Java では、ProcessBuilderProcessインスタンスを生成するために使用する方が適切です。これはProcessBuilder、子の stderr と stdout を同じストリームに結合できるためです。これにより、 によって返されたストリームからデータを読み取るだけで、単一のスレッド内で両方を使用できますprocess.getInputStream()

于 2012-12-10T19:15:36.447 に答える
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;
    }
}

これはうまくいきます。プロセスが終了し、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;
于 2012-12-11T08:32:05.410 に答える