2

私はAndroid用のターミナルエミュレーターを構築しようとしています。これはかなり新しいので、私のアイデアは、各コマンドを実行し、出力をファイルに保存することでした。ファイルの内容は、実行するたびに表示されます。 擬似コード:

public Boolean execCommands(String command) {
        try {
            rt = Runtime.getRuntime();
            process = rt.exec("su");
            DataOutputStream os = new DataOutputStream(process.getOutputStream());
            os.writeBytes("echo $ \""+command+ "\" >> /sdcard/Android/data/terminalemulatorlog.txt\n\n\n"); 
            /**** Note :  String command = (EditText)findViewById(R.id.command).getText().toString(); ****/
            os.flush();
            os.writeBytes("exit\n");
            os.flush();
            process.waitFor();
            }
        // Error Handling
        displayOutput(); //Loads and displays the Text File (/sdcard/Android/data/terminalemulatorlog.txt)
        return true;
        }

このコードは、いくつかの特別なコマンド(たとえば、「clear」)を除いて機能します。しかし、私がもっと心配しているのは、次の問題です。

  1. コマンドを実行するたびに、SuperUser権限(コードの2行目)を探すことになります。そして、私はこれを廃止したいと思います。

  2. ユーザーが次のように、あるコマンドの後に別のコマンドを入力した場合。

    cd /sdcard    
    touch File.txt    
    

    File.txtは、「/ sdcard」ではなく、「/」に作成されます。今のところ、これを避けるために、現在の作業ディレクトリが何であるかを把握するために、すべての「cd」コマンドを追跡しています。そして、私はこれを回避するより良い方法があることを望んでいます。

誰かがここで私を助けてくれたらありがたいです。

4

3 に答える 3

2

まだこれが必要かどうかはわかりませんが、これが一度に複数のコマンドを発行し、それらを実行するために「su」を使用しない方法です。

try {
    String[] commands = {           
            "dumpstate > /sdcard/LogFiles/dumpstate.txt",
            "dumpsys > /sdcard/LogFiles/dumpsys.txt",
            "logcat -d > /sdcard/LogFiles/log.txt",
            "cat /sdcard/LogFiles/dumpstate.txt /sdcard/LogFiles/dumpsys.txt /sdcard/LogFiles/log.txt > /sdcard/LogFiles/bugreport.rtf" };
    Process p = Runtime.getRuntime().exec("/system/bin/sh -");
    DataOutputStream os = new DataOutputStream(p.getOutputStream());
    for (String tmpCmd : commands) {
        os.writeBytes(tmpCmd + "\n");
    }
} catch (IOException e) {
    e.printStackTrace();
}
于 2012-02-02T19:50:50.703 に答える
2

これは少し遅いですが、ここではこれを行うためのいくつかの方法があります。

1)

開始点としてsuを使用する代わりに、/ system / bin/shを使用します。

と電話した後

rt.exec("/system/bin/sh");

さらにコマンドを実行するには、出力ストリームと入力ストリームを保持する必要があります。

コマンドを発行した後、「--- EOF ---」のような魔法の行をエコーし​​、その行を読み取った後、入力の読み取りを停止する必要があります。これがない場合は、InputStreamブロッキングからの読み取り関数になります。

2)データを作成したネイティブプロセスにパイプします。このプロセスでは、データをAndroidアプリケーションに移動し、最後に終了文字または文字列を付加します。

これを行う方法は完全にはわかりませんが、基本的には、前の方法が仲介者としてネイティブアプリケーションに依存しているのと同じです。

これにより、機能している「ターミナルエミュレータ」に近づくことができます。

3)真の端末エミュレーターが必要ない場合は、疑似端末への接続を開くネイティブアプリケーションを使用する以外に方法はありません。

ptyを開く方法の基本情報は次のとおりです:リンク

ターミナルエミュレータは、この手法を使用するオープンソースプロジェクトです。

こちらをご覧ください

于 2012-10-23T07:46:48.063 に答える
0

問題1について:

コマンドを実行するたびに、SuperUser権限(コードの2行目)を探すことになります。そして、私はこれを廃止したいと思います。

別の答えからのXonarの提案に感謝します:

コマンドを発行した後、「--- EOF ---」のような魔法の行をエコーし​​、その行を読み取った後、入力の読み取りを停止する必要があります。

Kotlinのソリューション:

private lateinit var suProcess: Process
private lateinit var outputStream: DataOutputStream

private fun getSu(): Boolean {
    return try {
        suProcess = Runtime.getRuntime().exec("su")
        outputStream = DataOutputStream(suProcess.outputStream)
        true
    } catch (e: Exception) {
        e.printStackTrace()
        false
    }
}

private fun sudo(command: String): List<String>? {
    return try {
        outputStream.writeBytes("$command\n")
        outputStream.flush()

        outputStream.writeBytes("echo ---EOF---\n")
        outputStream.flush()

        val reader = suProcess.inputStream.bufferedReader()
        val result = mutableListOf<String>()
        while (true) {
            val line = reader.readLine()
            if (line == "---EOF---") break
            result += line
        }

        result
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}

private fun exitTerminal() {
    try {
        outputStream.writeBytes("exit\n")
        outputStream.flush()

        suProcess.waitFor()
    } catch (e: Exception) {
        e.printStackTrace()
    } finally {
        outputStream.close()
    }
}

//Activity method
override fun onDestroy() {
    super.onDestroy()

    exitTerminal()
}
于 2020-02-05T14:12:37.720 に答える