簡體   English   中英

為 Android 構建終端模擬器

[英]Building a Terminal Emulator for Android

我一直在嘗試為 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;
        }

除了一些特殊命令(例如“清除”)之外,這段代碼可以正常工作。 但我更關心的是以下問題:

  1. 每次執行命令時,我最終都會尋求超級用戶權限(第二行代碼)。 我想取消這個。
  2. 如果用戶輸入一個命令,然后輸入另一個命令,
    如 :

     cd /sdcard touch File.txt

    File.txt是在“/”中創建的,而不是在“/sdcard”中。 到目前為止,為了避免這種情況,我正在跟蹤所有 'cd' 命令以找出當前的工作目錄是什么。 我希望有更好的方法來解決這個問題。

如果有人能在這里幫助我,我將不勝感激。

這有點晚了,但這里有幾種方法可以做到這一點。

1)

不要使用 su 作為起點,而是使用 /system/bin/sh。

並在調用后

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

您應該按住輸出流和輸入流以提供進一步的命令。

發出命令后,您應該回顯像“---EOF---”這樣的魔術行,並在閱讀該行后停止讀取輸入。 如果你沒有這個,你最終會得到來自 InputStream 阻塞的 read 函數。

2) 將數據通過管道傳輸到您編寫的本機進程,該進程只需將數據移動到您的 Android 應用程序,並在末尾附加終止字符或字符串。

我不完全確定如何執行此操作,但它與之前的方法本質上相同,只是依賴於您作為中間人的本機應用程序。

這將使您接近正常運行的“終端模擬器”。

3)如果您不需要真正的終端模擬器,那么除了使用本機應用程序打開與偽終端的連接之外,別無他法。

以下是有關如何打開 pty 的一些基本信息: 鏈接

Terminal Emulator 是一個使用這種技術的開源項目。

看看這里

不確定您是否仍然需要這個,但這是我一次發出多個命令而不使用“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();
}

關於問題1:

每次執行命令時,我最終都會尋求超級用戶權限(第二行代碼)。 我想取消這個。

感謝 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()
}

暫無
暫無

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

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