从 Android 应用程序中的 busybox 命令获取输出
Posted
技术标签:
【中文标题】从 Android 应用程序中的 busybox 命令获取输出【英文标题】:Getting output from busybox commands within Android app 【发布时间】:2012-04-21 13:22:28 【问题描述】:在我的一生中,我无法让我的应用从 su shell 中调用 busybox 的进程获取响应。
我尝试了三种不同的方法,也尝试了这三种方法的组合以使其工作,但我永远无法使用busybox从任何东西中获得输出,只能从其余命令获得输出。
更具体地说,我可以让它返回像ls /data
和cat suchandsuch.file
这样的命令,但是任何以“busybox”开头的东西(即busybox mount,busybox free)都不会显示任何东西。
这是最适合我的方法,此代码适用于 ls /data
,但不适用于“busybox free”
这个会运行命令(大部分情况下),并返回一个空字符串,而不是从输入流中无限循环。
Process p;
try
p = Runtime.getRuntime().exec(new String[]"su", "-c", "/system/bin/sh");
DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
stdin.writeBytes("ls /data\n");
DataInputStream stdout = new DataInputStream(p.getInputStream());
byte[] buffer = new byte[4096];
int read = 0;
String out = new String();
while(true)
read = stdout.read(buffer);
out += new String(buffer, 0, read);
if(read<4096)
break;
Toast.makeText(getApplicationContext(), out, Toast.LENGTH_SHORT).show();
catch (IOException e)
e.printStackTrace();
底部附近的 toast 显示了来自 ls /data
的所有内容,但是当为busybox 更改为任何内容时,其为空白或 null。
我也尝试了这两种方法,但都没有奏效。 (我在命令运行后将进程传递给他们。)
当您点击方法按钮时,这两者都会导致应用程序冻结。
String termReader(Process process)
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
try
int i;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
while ((i = reader.read(buffer)) > 0)
output.append(buffer, 0, i);
reader.close();
return output.toString();
catch (IOException e)
e.printStackTrace();
return e.getMessage();
String processReader(Process process)
InputStream stdout = process.getInputStream();
byte[] buffer = new byte[1024];
int read;
String out = new String();
while(true)
try
read = stdout.read(buffer);
out += new String(buffer, 0, read);
if(read<1024)
break;
catch (IOException e)
e.printStackTrace();
return out;
没有可使用的堆栈跟踪,所以我开始有点难过。
使用下面建议的代码进行编辑,嗯,下面:D 我对其进行了一些更改,使其成为一键运行的东西,以便于进行故障排除和测试。
当它尝试读取输入流时它也会冻结,如果我在尝试读取流之前调用stdin.writeBytes("exit\n")
,它会给我关闭终端的空白答案,如果我在之后调用它,它会无限循环。
void Run()
String command = "busybox traceroute\n";
StringBuffer theRun = null;
try
Process process = Runtime.getRuntime().exec("su");
DataOutputStream stdin = new DataOutputStream(process.getOutputStream());
stdin.writeBytes(command);
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
int read;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
while ((read = reader.read(buffer)) > 0)
theRun = output.append(buffer, 0, read);
reader.close();
process.waitFor();
catch (IOException e)
throw new RuntimeException(e);
catch (InterruptedException e)
throw new RuntimeException(e);
Toast.makeText(getApplicationContext(), theRun, Toast.LENGTH_SHORT).show();
它似乎跳过了第一行(每次调用命令时都会得到的 busybox 信息行)并且没有捕获其余数据。我已经尝试了我能想到的所有变体来让它正常工作:/
如果有人对此有所了解,我将不胜感激:)
【问题讨论】:
【参考方案1】:这是一个快速的解决方案...这是我为此创建的实用程序类。您可以使用本机 shell,如果设备已获得 root 权限,则可以使用 root shell,或者设置自定义 shell。给你。
https://github.com/jjNford/android-shell
【讨论】:
这是金子!谢谢!【参考方案2】:我找到了一种解决方法。
首先,在我的例子中,运行与busybox相关的命令永远不会通过它们的InputStream返回它们的输出,无论我尝试什么方法(我试过很多哈哈)。
这是我发现我可以做到的。这有点乏味,并且不会为您提供完整的输出,但是如果您想要依赖某个命令是否正确触发(在我的情况下,如果我无法比较所有内容,我的应用程序将无法正常工作跑了。)
你无法从进程中获取输入,但如果你工作正确,你可以获得退出值:) 这适用于任何不会给你复杂响应的东西(比如在大文件上使用 cat)
两者的区别很容易找到,例如:
command = "cat /sys" // works, exits with 1
command = "cat /init.rc" doesnt work, exits with 0
这就是我设置它以使其轻松工作的方式。使用 MasterJB 提供的方法正常运行命令:
process p;
try
p = Runtime.getRuntime().exec(new String[]"su", "-c", "/system/bin/sh");
DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
stdin.writeBytes(command);
stdin.writeBytes("echo $?\n");
DataInputStream stdout = new DataInputStream(p.getInputStream());
byte[] buffer = new byte[4096];
int read = 0;
String out = new String();
while(true)
read = stdout.read(buffer);
out += new String(buffer, 0, read);
if(read<4096)
break;
// here is where you catch the error value
int len = out.length();
char suExitValue = out.charAt(len-2);
Toast.makeText(getApplicationContext(), String.valueOf(suExitValue), Toast.LENGTH_SHORT).show();
return0or1(Integer.valueOf(suExitValue), command); // 0 or 1 Method
// end catching exit value
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
我还发现创建“0 或 1”方法来返回所发生的事情更容易。在这个例子中,它作为吐司被触发。您可能还想测试 char 是否实际上是一个整数,因为某些命令没有给出任何退出值(很奇怪,我知道。一个实例是 ls /sys,通过 su 终端运行时返回一个空白退出值。)
String return0or1 (int returnValue, String command)
String message = command + " - Cannot get return value.";
if (returnValue == 0)
message = command + " - successful.";
return message;
if (returnValue == 1)
message = command + " - failed.";
return message;
return message;
通过一些研究,您几乎可以将任何退出值与正确的响应相匹配,只需正确捕捉它们即可 :)
这些方法只返回命令是否运行(0),但如果它得到一个双字符或三字符的退出代码,当它失败时最后一个数字可能是 0(即当退出值为 10 时),所以这适用于大多数情况下,但需要扩展以捕获双倍和三倍值。
【讨论】:
以上是关于从 Android 应用程序中的 busybox 命令获取输出的主要内容,如果未能解决你的问题,请参考以下文章