Getting output from busybox commands in an Android application

Throughout my life I canโ€™t get my application to get a response from the process calling busybox from the su shell.

I tried three different methods, and also tried a combination of three to make it work, but I can never get the output from anything using busybox, only the rest of the commands.

To be more specific, I can make it return commands like "ls / data" and "cat suchandsuch.file", but everything that starts with "busybox" (like mountbox mount, busybox free) just doesn't show anything .

It was the method that was closest to me, this code works with "ls / data", but not "busybox free"

This will run the command (for the most part) and return an empty string instead of a loop infinitely from the input stream.

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(); } 

A toast near the bottom shows everything, starting with "ls / data", but when it is changed to something for busybox, its empty or zero value.

I also tried both of them, but they did not work. (I passed the process to them after running the command.)

Both of them will always cause the application to freeze when you click the button for the methods.

 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; } 

You have no stack traces to work with, so I'm a little confused.

Edited using the code below, uhm, below: D I modified it a bit to make it easy to use, to simplify troubleshooting and testing.

It also freezes when it tries to read the input stream, and if I call stdin.writeBytes ("exit \ n"), before trying to read the stream, it gives me an empty answer from closing the terminal, if I call it after, it loopes endlessly .

  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(); } 

It seems to skip the first line (the busybox info line that you get every time you invoke the command) and does not capture the rest of the data. Ive tried all the options that I can think of for this to work correctly: /

If anyone finds out about this, I would be very apreciative :)

+6
source share
2 answers

I found a peculiar solution for this.

First of all, running busybox related commands in my case will never return them via InputStream no matter what method I tried (And I tried ALOT LOL).

Here is what I learned that I can do. This is a little tedious and does not give you the full return, but if you want something to rely on whether the command was executed correctly (in my case, my application just does not work correctly if I can not compare how everything works.)

You cannot get input from the process, but you can get the exit value if you work correctly :) it works for everything that does not give you a complicated answer (for example, using cat in a large file)

the difference between them is easy to find, for example:

 command = "cat /sys" // works, exits with 1 command = "cat /init.rc" doesnt work, exits with 0 

This is how I set it up to work easily. Run the commands as usual using the method provided by 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(); } 

It was also easier for me to make the "0 or 1" method to return what happened. In this example, it was produced as a toast. you can also check if char is an integer since some commands do not give any exit value, which is always the case (wierd, I know. One instance is ls / sys, this returns an empty exit value when passing through su terminal.)

  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; } 

With a small amount of research, you can compare almost any output value with the correct answers, you just need to write them down correctly :)

these methods only return if the command was executed (0), but if it receives a double or triple char exit code, the last digit may be 0 when it failed (i.e. when the output value is 10), so this will be work in most cases, but they need to be expanded to catch double and triple values.

+1
source

Here is a quick solution ... This is the utility class that I created for this. You can use the native shell, the root shell, if the device is rooted or install a custom shell. Here you go.

https://github.com/jjNford/android-shell

+3
source

Source: https://habr.com/ru/post/912722/


All Articles