[HowTo]Execute Root Commands and read output

  • Thread starter Deleted member 4303594
  • Start date
Search This thread
D

Deleted member 4303594

Guest
You can learn here how to execute shell commands as root and read output and errors

What you will need:
  1. Eclipse with ADT plugin
  2. Basic knowledge of java
  3. Rooted android device

Note
Root commands should always be executed in background thread, you can use AsyncTask for example
I won't explain here how to use AsyncTask, maybe in another tut.

Also note that I'm a relative beginner myself so I won't use professional terms I'll try to explain in my own words, so I'm sorry in advance if you have no idea what I'm talking about :p

1. First thing that we need to do is open a new root shell like this:
Code:
 Process process = Runtime.getRuntime().exec("su");
Make sure to destroy this process after finished

2. Open input output and error streams to write commands and read output
Code:
OutputStream stdin = process.getOutputStream();
stdin is used to write commands to shell. This is OutputStream, which means that using this stream we can execute command(like writing command in terminal)
Code:
InputStream stderr = process.getErrorStream();
 InputStream stdout = process.getInputStream();
stderr and stdout are used to read output and error of a command which we executed.

3. Now we actually execute commands

Code:
 stdin.write(("ls\n").getBytes());
//after you exec everything that you want exit shell
stdin.write("exit\n".getBytes());

"\n" at the end of the command means new line(like when you press enter in terminal). This is important, if you dont add new line it same like you didn't press enter

4. Flush and close OutputStream

Code:
stdin.flush();   //flush stream
stdin.close(); //close stream

5. Read output and error of a executed command

Code:
BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
		           while ((line = br.readLine()) != null) {
		                Log.d("[Output]", line);
		            }
		            br.close();
		            br =
		                    new BufferedReader(new InputStreamReader(stderr));
		            while ((line = br.readLine()) != null) {
		            	Log.e("[Error]", line);
		            }
		            br.close();
We read output and error (if any) line by line and write it to logcat
You can of course do anything with output(display in TextView for example)
6. Finally we destroy opened shell
Code:
process.waitFor();//wait for process to finish
process.destroy();

You need to handle InteruptedException and IOException.

Hope this helps someone. Again sorry for stupid explanations. I totally understand all this but English isn't my primary language so its a but hard to explain...

Here is whole code;
Code:
		try {
		            String line;
		            Process process = Runtime.getRuntime().exec("su");
		            OutputStream stdin = process.getOutputStream();
		            InputStream stderr = process.getErrorStream();
		            InputStream stdout = process.getInputStream();

		            stdin.write(("ls\n").getBytes());
		             stdin.write("exit\n".getBytes());
		            stdin.flush();

		            stdin.close();
		            BufferedReader br =
		                    new BufferedReader(new InputStreamReader(stdout));
		            while ((line = br.readLine()) != null) {
		                Log.d("[Output]", line);
		            }
		            br.close();
		            br =
		                    new BufferedReader(new InputStreamReader(stderr));
		            while ((line = br.readLine()) != null) {
		            	Log.e("[Error]", line);
		            }
		            br.close();

					process.waitFor();
					process.destroy();

		        } catch (Exception ex) {
		        }
 
D

Deleted member 4303594

Guest
Yea roottools is better solution, it handles opening shell for you, its easier, less code, and in my experience a little bit faster.
Here is an example:
Code:
Command command = new Command(0, "ls")
{
       @Override
        public void output(int id, String line)
        {
          // Handle output here
        }
};
RootTools.getShell(true).add(command).waitForFinish();

And also do this when exiting application
Code:
RootTools.closeAllShells();

Sent from my Evo 3D GSM using Tapatalk 2
 

octobclrnts

Senior Member
Apr 26, 2009
67
13
Pittsburgh
I noticed that you called your InputStream stdout and your OutputStream stdin. Is there any reason that you chose to reverse the usual naming?
 
D

Deleted member 4303594

Guest
I noticed that you called your InputStream stdout and your OutputStream stdin. Is there any reason that you chose to reverse the usual naming?

Its confusing I know.
I'll try to explain

You use InputStream to read output of the shell so I called it stdout
Output of a shell/terminal is called stdout

You use OutputStream to write to shell(input to shell) so its stdin
Passing commands to terminal is stdin

It stands for standard output/input

More about stdin, stdout, stderr
http://en.m.wikipedia.org/wiki/Standard_streams

Sent from my Evo 3D GSM using Tapatalk 2
 
  • Like
Reactions: MattMatt0240
D

Deleted member 4303594

Guest
Great work but i would be delighted if op mentioned root commands and how to use them

There is no such thing as root command.
commands can be executed as root user or as normal user.

Sent from my Evo 3D GSM using Tapatalk 2
 
Last edited by a moderator:
D

Deleted member 4303594

Guest
You didn't get me sir I ment the commands which run as root and how can developers utilize them

Sent from my GT-S5302 using Tapatalk 2
Hit Thanx Button if i helped you!

I'm not really sure what you are asking. Any command can be executed as root.

Maybe you should read a bit about linux and shell

Sent from my Evo 3D GSM using Tapatalk 2
 

sak-venom1997

Senior Member
Feb 4, 2013
928
415
Lucknow
I'm not really sure what you are asking. Any command can be executed as root.

Maybe you should read a bit about linux and shell

Sent from my Evo 3D GSM using Tapatalk 2

No I was talking about the commands which require root to run like ifconfig

Sry for trouble I have no linux knowledge

Sent from my GT-S5302 using Tapatalk 2
Hit Thanx Button if i helped you!
 
Last edited:

nikwen

Senior Member
Feb 1, 2013
3,142
1,597
Berlin, Germany
www.nikwen.de
No I was talking about the commands which require root to run like ifconfig

Sry for trouble I have no linux knowledge

Sent from my GT-S5302 using Tapatalk 2
Hit Thanx Button if i helped you!

There are some commands that will just make sense as root. However, why should anyone write a tutorial about how to use some commands very few persons will need. Google "Linux command <what you want to do>" and you will find explanations. Many commands are just more flexible when executed like this.
I really recommend that. You will need it when you develop a root app. And you can use the adb shell! Great help.

@OP: What's about mentioning that you should use the busybox commands as the system's implementation of the shell commands differs from device to device and from ROM to ROM?

I also recommend RootTools. One of the best libraries in my opinion!
 
D

Deleted member 4303594

Guest
.
@OP: What's about mentioning that you should use the busybox commands as the system's implementation of the shell commands differs from device to device and from ROM to ROM?

I also recommend RootTools. One of the best libraries in my opinion!

Purpose of this tutorial is to show how to execute commands as root, not how to use certain Linux commands.

And besides, using busybox is not always best solution, what if device doesn't have it installed, what if busybox doesn't have that command.
For example you would definitely not use "busybox echo" or "busybox ls".
Devs should already know how to use Linux, this is just to show how to do it from java.

Sent from my Evo 3D GSM using Tapatalk 2
 
  • Like
Reactions: NineInchNails

nikwen

Senior Member
Feb 1, 2013
3,142
1,597
Berlin, Germany
www.nikwen.de
Purpose of this tutorial is to show how to execute commands as root, not how to use certain Linux commands.

And besides, using busybox is not always best solution, what if device doesn't have it installed, what if busybox doesn't have that command.
For example you would definitely not use "busybox echo" or "busybox ls".

You are right. It is true that nobody would use busybox for very simple commands.

However, RootTools has the RootTools.offerBusyBox(Activity activity) Method which opens Google Play to download a busybox installer.

Devs should already know how to use Linux, this is just to show how to do it from java.

Sent from my Evo 3D GSM using Tapatalk 2

I understood what you wanted to do.

Great job, btw. Would have been glad if I had had this when I started with root apps. ;)
 

ramdroid77

Senior Member
May 7, 2009
827
127
Purpose of this tutorial is to show how to execute commands as root, not how to use certain Linux commands.

And besides, using busybox is not always best solution, what if device doesn't have it installed, what if busybox doesn't have that command.
For example you would definitely not use "busybox echo" or "busybox ls".
Devs should already know how to use Linux, this is just to show how to do it from java.

Sent from my Evo 3D GSM using Tapatalk 2

I once did run into troubles parsing the results of "ls" command. Usually 'ls' is just the short table-style list, while you could get all the details with 'ls -l'. This is what I needed. But when testing on the Motorola Milestone unfortunately 'ls' was sym-linked to 'ls -l', therefore calling 'ls -l' would result in an error message. Don't know if more devices act like that (didn't test on any other Motorola phones, and the Milestone is quite old by now), but maybe it still makes sense to use busybox for 'normal' command in some cases...
 
  • Like
Reactions: nikwen

abcdjdj

Senior Member
May 28, 2012
1,732
3,228
Thane
Hello,

I am trying to run a script kept in my assests folder of my app. It is Root.sh which contains -
Code:
su
cd system
mkdir abcdjdj

This is my java code:-
Code:
String path = "file:///android_asset/Root.sh";
Process p = new ProcessBuilder().command(path).start();

But now I get a runtime error -
Code:
04-22 15:08:03.144: E/AndroidRuntime(785): Caused by: java.io.IOException: Error running exec(). Command: [file:///android_asset/Root.sh] Working Directory: null Environment: [ANDROID_SOCKET_zygote=9, ANDROID_STORAGE=/storage, ANDROID_BOOTLOGO=1, EXTERNAL_STORAGE=/mnt/sdcard, ANDROID_ASSETS=/system/app, PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin, ASEC_MOUNTPOINT=/mnt/asec, LOOP_MOUNTPOINT=/mnt/obb, BOOTCLASSPATH=/system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/mms-common.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar, ANDROID_DATA=/data, LD_LIBRARY_PATH=/vendor/lib:/system/lib, ANDROID_ROOT=/system, ANDROID_PROPERTY_WORKSPACE=8,32768]

Can anyone please help me?

Thanks.
 

nikwen

Senior Member
Feb 1, 2013
3,142
1,597
Berlin, Germany
www.nikwen.de
Hello,

I am trying to run a script kept in my assests folder of my app. It is Root.sh which contains -
Code:
su
cd system
mkdir abcdjdj

This is my java code:-
Code:
String path = "file:///android_asset/Root.sh";
Process p = new ProcessBuilder().command(path).start();

But now I get a runtime error -
Code:
04-22 15:08:03.144: E/AndroidRuntime(785): Caused by: java.io.IOException: Error running exec(). Command: [file:///android_asset/Root.sh] Working Directory: null Environment: [ANDROID_SOCKET_zygote=9, ANDROID_STORAGE=/storage, ANDROID_BOOTLOGO=1, EXTERNAL_STORAGE=/mnt/sdcard, ANDROID_ASSETS=/system/app, PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin, ASEC_MOUNTPOINT=/mnt/asec, LOOP_MOUNTPOINT=/mnt/obb, BOOTCLASSPATH=/system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/mms-common.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar, ANDROID_DATA=/data, LD_LIBRARY_PATH=/vendor/lib:/system/lib, ANDROID_ROOT=/system, ANDROID_PROPERTY_WORKSPACE=8,32768]

Can anyone please help me?

Thanks.

Why don't you do it this way?

Code:
Runtime.getRuntime().exec("su", "-c", "cd system; mkdir abcdjdj");

Note that you need to pass the commands you want to execute to the command method, not the path.
 
  • Like
Reactions: abcdjdj

abcdjdj

Senior Member
May 28, 2012
1,732
3,228
Thane
Why don't you do it this way?

Code:
Runtime.getRuntime().exec("su", "-c", "cd system; mkdir abcdjdj");

Note that you need to pass the commands you want to execute to the command method, not the path.

It gives a syntax error. I guess it should have been - Runtime.getRuntime().exec(new String[] { "su", "-c", "cd system; mkdir abcdjdj" });
It runs fine on my phone but I still don't see a folder called abcdjdj is /system
 

nikwen

Senior Member
Feb 1, 2013
3,142
1,597
Berlin, Germany
www.nikwen.de
It gives a syntax error. I guess it should have been - Runtime.getRuntime().exec(new String[] { "su", "-c", "cd system; mkdir abcdjdj" });
It runs fine on my phone but I still don't see a folder called abcdjdj is /system

You are right, it should have been that.

Try to add the full path:

Code:
Runtime runtime = Runtime.getRuntime();
try {
	runtime.exec(new String[] {"su", "-c", "mkdir /system/abcdef"});
	runtime.exec(new String[] {"su", "-c", "mkdir /system/aaab; mkdir /system/aaac"});
} catch (IOException e) {
	e.printStackTrace();
}

I think that executing your first idea should work if you execute
Code:
runtime.exec("su");
and then write the commands to the outputstream as described in the first post of this thread.

---------- Post added at 06:13 PM ---------- Previous post was at 06:06 PM ----------

However, I recommend using roottools.
If you need to execute commands rarely it will be fine that way, but if you need to execute commands often, there will be annoying Toast messages every time. Using roottools, there will be such a message just once when the app requests SU rigths for the first time after the launch.
 
Last edited:

Top Liked Posts

  • There are no posts matching your filters.
  • 15
    D
    Deleted member 4303594
    You can learn here how to execute shell commands as root and read output and errors

    What you will need:
    1. Eclipse with ADT plugin
    2. Basic knowledge of java
    3. Rooted android device

    Note
    Root commands should always be executed in background thread, you can use AsyncTask for example
    I won't explain here how to use AsyncTask, maybe in another tut.

    Also note that I'm a relative beginner myself so I won't use professional terms I'll try to explain in my own words, so I'm sorry in advance if you have no idea what I'm talking about :p

    1. First thing that we need to do is open a new root shell like this:
    Code:
     Process process = Runtime.getRuntime().exec("su");
    Make sure to destroy this process after finished

    2. Open input output and error streams to write commands and read output
    Code:
    OutputStream stdin = process.getOutputStream();
    stdin is used to write commands to shell. This is OutputStream, which means that using this stream we can execute command(like writing command in terminal)
    Code:
    InputStream stderr = process.getErrorStream();
     InputStream stdout = process.getInputStream();
    stderr and stdout are used to read output and error of a command which we executed.

    3. Now we actually execute commands

    Code:
     stdin.write(("ls\n").getBytes());
    //after you exec everything that you want exit shell
    stdin.write("exit\n".getBytes());

    "\n" at the end of the command means new line(like when you press enter in terminal). This is important, if you dont add new line it same like you didn't press enter

    4. Flush and close OutputStream

    Code:
    stdin.flush();   //flush stream
    stdin.close(); //close stream

    5. Read output and error of a executed command

    Code:
    BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
    		           while ((line = br.readLine()) != null) {
    		                Log.d("[Output]", line);
    		            }
    		            br.close();
    		            br =
    		                    new BufferedReader(new InputStreamReader(stderr));
    		            while ((line = br.readLine()) != null) {
    		            	Log.e("[Error]", line);
    		            }
    		            br.close();
    We read output and error (if any) line by line and write it to logcat
    You can of course do anything with output(display in TextView for example)
    6. Finally we destroy opened shell
    Code:
    process.waitFor();//wait for process to finish
    process.destroy();

    You need to handle InteruptedException and IOException.

    Hope this helps someone. Again sorry for stupid explanations. I totally understand all this but English isn't my primary language so its a but hard to explain...

    Here is whole code;
    Code:
    		try {
    		            String line;
    		            Process process = Runtime.getRuntime().exec("su");
    		            OutputStream stdin = process.getOutputStream();
    		            InputStream stderr = process.getErrorStream();
    		            InputStream stdout = process.getInputStream();
    
    		            stdin.write(("ls\n").getBytes());
    		             stdin.write("exit\n".getBytes());
    		            stdin.flush();
    
    		            stdin.close();
    		            BufferedReader br =
    		                    new BufferedReader(new InputStreamReader(stdout));
    		            while ((line = br.readLine()) != null) {
    		                Log.d("[Output]", line);
    		            }
    		            br.close();
    		            br =
    		                    new BufferedReader(new InputStreamReader(stderr));
    		            while ((line = br.readLine()) != null) {
    		            	Log.e("[Error]", line);
    		            }
    		            br.close();
    
    					process.waitFor();
    					process.destroy();
    
    		        } catch (Exception ex) {
    		        }
    3
    What is the advantage of CMD processor?

    Btw, you are one of the best programmers I have ever seen assisting others with programming apps on xda.
    Well I'd say the advantage is that it's lighter than the roottools jar and the syntax to call it is more concise (no try/catch needed). But I guess roottools has more features, idk, didn't use it very much

    Thanks a lot for the compliment, I could say the same about you ;)
    I try to help when I can but I really don't have much experience, for example I wouldn't have been able to answer the animation question you answered.
    I started java & android apps about 6 months ago but I'm lucky enough to work from home so I have a lot of time to practice & learn everyday.

    I love this new app development forum and I hope it will be more active soon (and that we'll get syntax highlighting eventually!)
    2
    Just my 2 cents, but the CMDProcessor helper class is a good alternative to RootTools.
    I don't know who brought it up first (I know I grabbed it from AOKP) but all credits goes to him/her/them

    to execute a root command just call it like that :
    Code:
    CMDProcessor cmd = new CMDProcessor();
    cmd.su.runWaitFor("echo hello world > /sdcard/cmd.txt");

    But it has may other static methods allowing to grab the output, check for root, for busybox, etc... The methods's names are usually pretty explicit, and if they're not, the code they contain is.

    I'll paste my version here :
    Code:
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.InputStream;
    
    import android.util.Log;
    
    public class CMDProcessor {
    
    	private final String TAG = getClass().getSimpleName();
    	private static final boolean DEBUG = false;
    	private Boolean can_su;
    	public SH sh;
    	public SH su;
    
    	public CMDProcessor() {
    		sh = new SH("sh");
    		su = new SH("su");
    	}
    
    	public SH suOrSH() {
    		return canSU() ? su : sh;
    	}
    
    	public boolean canSU() {
    		return canSU(false);
    	}
    
    	public class CommandResult {
    		private final String resultTag = TAG + '.' + getClass().getSimpleName();
    		public final String stdout;
    		public final String stderr;
    		public final Integer exit_value;
    
    		CommandResult(final Integer exit_value_in) {
    			this(exit_value_in, null, null);
    		}
    
    		CommandResult(final Integer exit_value_in, final String stdout_in,
    				final String stderr_in) {
    			exit_value = exit_value_in;
    			stdout = stdout_in;
    			stderr = stderr_in;
    			if (DEBUG)
    				Log.d(TAG, resultTag + "( exit_value=" + exit_value
    						+ ", stdout=" + stdout + ", stderr=" + stderr + " )");
    		}
    
    		public boolean success() {
    			return exit_value != null && exit_value == 0;
    		}
    
    	}
    
    	public class SH {
    		private String SHELL = "sh";
    
    		public SH(final String SHELL_in) {
    			SHELL = SHELL_in;
    		}
    
    		private String getStreamLines(final InputStream is) {
    			String out = null;
    			StringBuffer buffer = null;
    			final DataInputStream dis = new DataInputStream(is);
    			try {
    				if (dis.available() > 0) {
    					buffer = new StringBuffer(dis.readLine());
    					while (dis.available() > 0) {
    						buffer.append("\n").append(dis.readLine());
    					}
    				}
    				dis.close();
    			} catch (final Exception ex) {
    				Log.e(TAG, ex.getMessage());
    			}
    			if (buffer != null) {
    				out = buffer.toString();
    			}
    			return out;
    		}
    
    		public Process run(final String s) {
    			Process process = null;
    			try {
    				process = Runtime.getRuntime().exec(SHELL);
    				final DataOutputStream toProcess = new DataOutputStream(
    						process.getOutputStream());
    				toProcess.writeBytes("exec " + s + "\n");
    				toProcess.flush();
    			} catch (final Exception e) {
    				Log.e(TAG,
    						"Exception while trying to run: '" + s + "' "
    								+ e.getMessage());
    				process = null;
    			}
    			return process;
    		}
    
    		public CommandResult runWaitFor(final String s) {
    			if (DEBUG)
    				Log.d(TAG, "runWaitFor( " + s + " )");
    			final Process process = run(s);
    			Integer exit_value = null;
    			String stdout = null;
    			String stderr = null;
    			if (process != null) {
    				try {
    					exit_value = process.waitFor();
    					stdout = getStreamLines(process.getInputStream());
    					stderr = getStreamLines(process.getErrorStream());
    				} catch (final InterruptedException e) {
    					Log.e(TAG, "runWaitFor " + e.toString());
    				} catch (final NullPointerException e) {
    					Log.e(TAG, "runWaitFor " + e.toString());
    				}
    			}
    			return new CommandResult(exit_value, stdout, stderr);
    		}
    	}
    
    	public boolean canSU(final boolean force_check) {
    		if (can_su == null || force_check) {
    			final CommandResult r = su.runWaitFor("id");
    			final StringBuilder out = new StringBuilder();
    			if (r.stdout != null) {
    				out.append(r.stdout).append(" ; ");
    			}
    			if (r.stderr != null) {
    				out.append(r.stderr);
    			}
    			Log.d(TAG, "canSU() su[" + r.exit_value + "]: " + out);
    			can_su = r.success();
    		}
    		return can_su;
    	}
    }

    What is the advantage of CMD processor?

    Btw, you are one of the best programmers I have ever seen assisting others with programming apps on xda.
    1
    Everyone should read the How-To SU guide by Chainfire:

    http://su.chainfire.eu/

    Usable example code is on Github. In the meanwhile there's an interactive shell (like in RootTools) available too:

    https://github.com/Chainfire/libsuperuser
    1
    I had not done that. Now I did and it is working absolutely perfect.:D

    Great. :good: