[英]Building a Terminal Emulator for Android
I've been trying to build a Terminal Emulator for Android.我一直在尝试为 Android 构建终端模拟器。 Being pretty new to this, my idea was to execute each command and store the output in a file, whose contents would be displayed after each execution.
对此很陌生,我的想法是执行每个命令并将输出存储在一个文件中,其内容将在每次执行后显示。 Pseudo Code :
伪代码:
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;
}
This piece of code works except for a few special commands (Eg. 'clear').除了一些特殊命令(例如“清除”)之外,这段代码可以正常工作。 But what I'm more concerned about are the following problems :
但我更关心的是以下问题:
In cases when the user enters one command followed by another,如果用户输入一个命令,然后输入另一个命令,
Such as :如 :
cd /sdcard touch File.txt
The File.txt is created in '/' and not in '/sdcard'. File.txt是在“/”中创建的,而不是在“/sdcard”中。 As of now to avoid this, I'm keeping a track of all the 'cd' commands to figure out what the present working directory is.
到目前为止,为了避免这种情况,我正在跟踪所有 'cd' 命令以找出当前的工作目录是什么。 And I'm hoping that there is a better way around this.
我希望有更好的方法来解决这个问题。
I'd be grateful if someone could help me out here.如果有人能在这里帮助我,我将不胜感激。
This a bit late but here a few ways of doing this.这有点晚了,但这里有几种方法可以做到这一点。
1) 1)
Instead of using su as a starting point use /system/bin/sh.不要使用 su 作为起点,而是使用 /system/bin/sh。
and after calling并在调用后
rt.exec("/system/bin/sh");
You should hold onto the Output Stream and Input Stream to give further commands.您应该按住输出流和输入流以提供进一步的命令。
After you issued a command you should echo a magic line like "---EOF---" and stop reading input after reading that line.发出命令后,您应该回显像“---EOF---”这样的魔术行,并在阅读该行后停止读取输入。 If you don't have this you'll end up with the read function from the InputStream blocking.
如果你没有这个,你最终会得到来自 InputStream 阻塞的 read 函数。
2) Pipe the data to a native process you've written that simply moves the data on to your Android Application with a terminating character or string attached to the end. 2) 将数据通过管道传输到您编写的本机进程,该进程只需将数据移动到您的 Android 应用程序,并在末尾附加终止字符或字符串。
I am not entirely sure how to do this, but it is essentially the same as the previous method just relies on you native application as a middle man.我不完全确定如何执行此操作,但它与之前的方法本质上相同,只是依赖于您作为中间人的本机应用程序。
This will get you close to a functioning "Terminal Emulator".这将使您接近正常运行的“终端模拟器”。
3)If you wan't a true Ternimal Emulator then there's no other way to do it than : using a native application that opens a connection to a psuedoterminal. 3)如果您不需要真正的终端模拟器,那么除了使用本机应用程序打开与伪终端的连接之外,别无他法。
Here's some basic information of how to open a pty : link以下是有关如何打开 pty 的一些基本信息: 链接
Terminal Emulator is a open source project that uses this technique. Terminal Emulator 是一个使用这种技术的开源项目。
Not sure if you are still needing this or not, but here is how I am issuing multiple commands at one time and not using "su" to have them run.不确定您是否仍然需要这个,但这是我一次发出多个命令而不使用“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();
}
Regarding problem 1:关于问题1:
Each time a command is to be executed, I end up seeking SuperUser permissions (second line of code).
每次执行命令时,我最终都会寻求超级用户权限(第二行代码)。 And I'd like to do away with this.
我想取消这个。
Thanks to Xonar's suggestion from another answer:感谢 Xonar 从另一个答案中提出的建议:
After you issued a command you should echo a magic line like "---EOF---" and stop reading input after reading that line.
发出命令后,您应该回显像“---EOF---”这样的魔术行,并在阅读该行后停止读取输入。
Solution in Kotlin: 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.