我一直在尝试为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')之外,这段代码可以正常工作。 但我更关心的是以下问题:
如果用户输入一个命令后跟另一个命令,则为 如:
cd /sdcard
touch File.txt
File.txt 在'/'中创建,而不是在'/ sdcard'中创建。到目前为止,为了避免这种情况,我将跟踪所有'cd'命令,以确定当前工作目录是什么。而且我希望有更好的解决方法。
如果有人能帮助我,我将不胜感激。
答案 0 :(得分: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();
}
答案 1 :(得分:1)
这有点晚了,但这里有几种方法。
1)
而不是使用su作为起点使用/ system / bin / sh。
并在致电后
rt.exec("/system/bin/sh");
您应该抓住输出流和输入流以提供更多命令。
发出命令后,您应该回显“--- EOF ---”之类的魔术线,并在读取该行后停止读取输入。如果你没有这个,你将最终得到InputStream阻塞的读取函数。
2)将数据传输到您编写的本机进程,该进程只是将数据移动到您的Android应用程序,并在终端附加一个终止字符或字符串。
我不完全确定如何做到这一点,但它与以前的方法基本相同,只是依赖于您作为中间人的原生应用程序。
这将使您接近功能正常的“终端模拟器”。
3)如果你不是真正的Ternimal Emulator,那么没有别的方法可以做到:使用打开与psuedoterminal连接的本机应用程序。
以下是有关如何打开pty的一些基本信息:link
Terminal Emulator是一个使用这种技术的开源项目。
看看here
答案 2 :(得分:0)
关于问题1:
每次执行命令时,我最终都会寻求SuperUser权限(第二行代码)。我想消除这个问题。
感谢Xonar从另一个答案中提出的建议:
发出命令后,您应该回显一条神奇的行,例如“ --- EOF ---”,并在读取该行之后停止读取输入。
科特林的解决方案:
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()
}