[DEV GUIDE][2016.12.22] How-To SU

Search This thread

Xuuuud

New member
Jun 9, 2013
4
0
Hello,

I have a problem. I am trying to manage streams of a single background process instance returned by Runtime.getRuntime().exec("su") throughout my app. After writing a command, say "mount -o rw,remount /system" to the output stream, a confusing blocking error of the input stream arises when I want to read that stream, even in a worker thread, and in which condition there turns out to be some unexpected results.

Is there any advice or example for me to avoid it?
 

windflyer

New member
Jan 16, 2013
2
0
Wuhan
I am curious why you said "ProcessBuilder does not work consistently across all Android versions", any evidence or reference?

Thanks.
 

Chainfire

Moderator Emeritus / Senior Recognized Developer
Oct 2, 2007
11,451
87,852
www.chainfire.eu
I am curious why you said "ProcessBuilder does not work consistently across all Android versions", any evidence or reference?

This is from memory, but what I recall is passing a line of commands both quoted as well as unquoted as a single argument to PB ("su", "-c", "...commands...") didn't consistently arrive as a single parameter to the su binary, depending on (now ancient) Android versions. This is from very long ago though, I'm not even sure I'm remembering it right.
 

windflyer

New member
Jan 16, 2013
2
0
Wuhan
This is from memory, but what I recall is passing a line of commands both quoted as well as unquoted as a single argument to PB ("su", "-c", "...commands...") didn't consistently arrive as a single parameter to the su binary, depending on (now ancient) Android versions. This is from very long ago though, I'm not even sure I'm remembering it right.

Thanks for you reply. Actually, I have not met any open-source android apps that use ProcessBuilder yet.
 

GENiALi

New member
Feb 24, 2009
3
0
blog.geniali.ch
OnCommandResultListener bevor all OnSTDOUTLineListener liOnCommandResultLnes are send

Hi
I will use ping with libsuperuser. I use this code.
Code:
shShell = new Shell.Builder().useSH()
	 .setWantSTDERR(true)
	 .setOnSTDERRLineListener(new StreamGobbler.OnLineListener() {
		 @Override
		 public void onLine(String line) {
			 //Error
		 }
	 })
	 .setOnSTDOUTLineListener(new StreamGobbler.OnLineListener() {
		 @Override
		 public void onLine(String line) {
			 //Line
		 }
	 })
	 .open(new Shell.OnCommandResultListener() {
		 @Override
		 public void onCommandResult(int commandCode, int exitCode, List<String> output) {
			 //Finish
		 }
	 });

shShell.addCommand("/system/bin/ping -c 3 google.com");
But, OnCommandResultListener call bevor all lines are sended. In the output list ar this:
-BOC-
uid=10154(u0_a154) gid=10154(u0_a154) groups=1028(sdcard_r),3003(inet)

Not the output from ping. How can I determine whether the ping is done?
 

GENiALi

New member
Feb 24, 2009
3
0
blog.geniali.ch
Attach the OnCommandResultListener to the addCommand call instead
I have.
I will a output line for line AND an info when ping is finished.
OnCommandResultListener must call AFTER send the last line in setOnSTDOUTLineListener.
How do this.

setOnSTDOUTLineListener-> Line
setOnSTDOUTLineListener-> Line
setOnSTDOUTLineListener-> Line
setOnSTDOUTLineListener-> Line
setOnSTDOUTLineListener-> Last line
OnCommandResultListener -> all lines

Not this.
setOnSTDOUTLineListener-> Line
setOnSTDOUTLineListener-> Line
OnCommandResultListener -> all lines
setOnSTDOUTLineListener-> Line
setOnSTDOUTLineListener-> Line
setOnSTDOUTLineListener-> Last line
 
Last edited:

Chainfire

Moderator Emeritus / Senior Recognized Developer
Oct 2, 2007
11,451
87,852
www.chainfire.eu
No guarantees are made regarding the order the callbacks are being called. These are not normally called together and may be handled by different threads directly, or posted to handlers.
 

Burn02

Senior Member
Feb 1, 2010
419
78
Hello, sorry to disturb you, i have got one question.

I use for the moment rootools, but i have got a pb with it. I do not succed to run a root command in a background process.
That is to say that it works when phone is on (i could toggle it in background). But when phone is sleeping, it's just wait until phone is on to run it.
It's not a service problem has it works for all non root action.
I do not know why and do not have any answer from the team that developp it.


So this is why i will try to use libsuperuser. The question is, is there any solution with your lib to put in airplane mode from a service in backend?
I expect that your lib could solve this problem. :)


EDIT: i never find a way to test your exemple if i compile it from eclipse:
[2013-11-12 01:02:21 - Dex Loader] Unable to execute dex: java.nio.BufferOverflowException. Check the Eclipse log for stack trace.
[2013-11-12 01:02:21 - libsuperuser_example] Conversion to Dalvik format failed: Unable to execute dex: java.nio.BufferOverflowException. Check the Eclipse log for stack trace.

I did not succed to test your lib. :/ Is there any more easy exemple just to run a root command with your lib? :/

I have tested to import the lib in my project, add it to the reference, export it to the apk just do a
Shell.SU.available()

Application crash.

I never succed to use it. :/


EDIT: i find a way to use it, i will test to see if it sole my problem for put phone into airplane mode.
 
Last edited:

Burn02

Senior Member
Feb 1, 2010
419
78
My bad. I got exactly the same problem that i always have from rootools. :(

I do not succed to send a root command in background, it always wait until phone is on to run it.. Does someone could help me? :crying:

Here is the problem, i am trying to toggle airplane mode in back ground, with a service, that could run when phone is sleeping.

The problem is that i do not find any way to run a root action when phone is sleeping. The service lunch, run, and is waiting something on the line who do the root action.

It's alsways the same thing on rootools, libsuperuser, i have tried a lot of things, and always the same problem. Could you help me and explain how i could do it?

Thank's a lot.

I have found a way to contourn this problem!!!

PowerManager pm = (PowerManager)m_context.getSystemService(Context.POWER_SERVICE);
owerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK| PowerManager.ACQUIRE_CAUSES_WAKEUP, "Sleepytux");
wl.acquire();
//do your root action
wl.release();

And it works!!! :)
 
Last edited:

mikereidis

Inactive Recognized Developer
Jan 28, 2011
7,823
4,146
Ottawa/Gatineau, Canada
The guide has been updated to revision 1.40, adding information about SELinux/SEAndroid and some upcoming drama from Android 4.5

Thank you. :)


Is there anything in recent AOSP that explains why using SU to chmod /dev/snd/pcmC0D0c fails now ?

And yet chmod on /dev/snd/controlC0 is fine ?

It appears that the chmod within toolbox attempts to open the device node, which fails with bad parameters.

My workaround has been to use my own copy of busybox, whose chmod works fine.

I don't know if Google broke this on purpose or not.

I can't think of a cleaner workaround and suspect this could break at some point.
 

wtfrtfmdiy

New member
Aug 25, 2014
1
0
command hangs

Guide updated to v1.50 with even more new things about SELinux and the upcoming Android release - ....

Also be sure to check out my G+ post about the subject here:...

Hi Chainfire ,
a quick question:
is there a know bug which prevents correct execution using your libs and supersu 0.98?
I'm running AOSP 4.3 on nexus 4 and I tried both:
SH.run("su","id>/data/data/log.txt");
SU.run("id>/data/data/log.txt");
The waitFor returns after 2/3 min with ret =1, the file has not been created.
If i do from adb shell : "su -c id" or "su -c "id>/data/data/log.txt" each commands work flawless.
Many thanks
 

andQlimax

Senior Member
Jul 29, 2010
2,562
1,003
Rome
Samsung Galaxy S23 Ultra
Hi @Chainfire
Before Android L, I was successfully using root permissions thanks to your How to SU guide.

Basically in my app I need to execute an sqlite3 binary from my app data directory /data/data/<package>/sqlite3
Now this was working fine by using this simple line of code:

Code:
Shell.SU.run(commands);

where commands is something like "/data/data/<package>/sqlite3 ..."

Now with Android L and selinux things, I'm trying to do something like this:

Code:
Shell.run(Shell.SU.shell(0, "u:r:untrusted_app:s0"), commands.toArray(new String[commands.size()]), null, true);

But if I print the result I get a permission denied from the binary (which I give execute permission as usual with shell, without su).
This still works fine on a Nexus 5 with Android 4.4.4 but not on Android L (both with latest superSU).

Where I wrong? Any tip? Thanks in advance
 
Last edited:

Chainfire

Moderator Emeritus / Senior Recognized Developer
Oct 2, 2007
11,451
87,852
www.chainfire.eu
Hi @Chainfire
Before Android L, I was successfully using root permissions thanks to your How to SU guide.

Basically in my app I need to execute an sqlite3 binary from my app data directory /data/data//sqlite3
Now this was working fine by using this simple line of code:

Code:
Shell.SU.run(commands);

where commands is something like "/data/data//sqlite3 ..."

Now with Android L and selinux things, I'm trying to do something like this:

Code:
Shell.run(Shell.SU.shell(0, "u:r:untrusted_app:s0"), commands.toArray(new String[commands.size()]), null, true);

But if I print the result I get a permission denied from the binary (which I give execute permission as usual with shell, without su).
This still works fine on a Nexus 5 with Android 4.4.4 but not on Android L (both with latest superSU).

Where I wrong? Any tip? Thanks in advance

Check logcat and/or audit logs to see what exactly has been blocked, is the place to start.
 

andQlimax

Senior Member
Jul 29, 2010
2,562
1,003
Rome
Samsung Galaxy S23 Ultra
Check logcat and/or audit logs to see what exactly has been blocked, is the place to start.

Today I got some free time and I was trying again to make my root app to work on android L, but I still didn't managed it.
Following the error that I get:
Code:
10-07 21:35:57.569    6429-6616/? D/libsuperuser﹕ [libsuperuser][C][SU -V%] START
10-07 21:35:57.584    6429-6616/? D/libsuperuser﹕ [libsuperuser][C][SU -V%] END
10-07 21:35:57.584    6429-6616/? D/libsuperuser﹕ [libsuperuser][C][SU -V%] START
10-07 21:35:57.594    6429-6620/? D/libsuperuser﹕ [libsuperuser][O][SU -V-] 2.02:SUPERSU
10-07 21:35:57.599    6429-6616/? D/libsuperuser﹕ [libsuperuser][C][SU -V%] END
10-07 21:35:57.599    6429-6616/? D/libsuperuser﹕ [libsuperuser][C][SU%] START
10-07 21:35:57.608    6429-6625/? D/libsuperuser﹕ [libsuperuser][O][SU -V-] 202
10-07 21:35:57.614    6429-6616/? D/libsuperuser﹕ [libsuperuser][C][SU+] /data/data/com.andqlimax.pushfixer/sqlite3 /data/data/com.google.android.gsf/databases/gservices.db " < ... snip ... > ";
10-07 21:35:57.609    6632-6632/? I/auditd﹕ type=1400 audit(0.0:332): avc:  denied  { sys_ptrace } for  comm="daemonsu" capability=19  scontext=u:r:init:s0 tcontext=u:r:init:s0 tclass=capability
10-07 21:35:57.609    6635-6635/? I/auditd﹕ type=1400 audit(0.0:333): avc:  denied  { sys_ptrace } for  comm="daemonsu" capability=19  scontext=u:r:init:s0 tcontext=u:r:init:s0 tclass=capability
10-07 21:35:57.609    6635-6635/? I/auditd﹕ type=1400 audit(0.0:334): avc:  denied  { sys_ptrace } for  comm="daemonsu" capability=19  scontext=u:r:init:s0 tcontext=u:r:init:s0 tclass=capability
10-07 21:35:57.609    6635-6635/? I/auditd﹕ type=1400 audit(0.0:335): avc:  denied  { sys_ptrace } for  comm="daemonsu" capability=19  scontext=u:r:init:s0 tcontext=u:r:init:s0 tclass=capability
10-07 21:35:57.619    6635-6635/? I/auditd﹕ type=1400 audit(0.0:336): avc:  denied  { execute } for  comm="tmp-mksh" name="sqlite3" dev="mmcblk0p28" ino=1426546 scontext=u:r:init:s0 tcontext=u:object_r:app_data_file:s0 tclass=file
10-07 21:35:57.628    6429-6631/? D/libsuperuser﹕ [libsuperuser][O][SU*] tmp-mksh: <stdin>[7]: /data/data/com.andqlimax.pushfixer/sqlite3: can't execute: Permission denied
10-07 21:35:57.630    6429-6616/? D/libsuperuser﹕ [libsuperuser][C][SU%] END

Code:
root@hammerhead:/data/data/com.andqlimax.pushfixer # ls -l                     
drwxrwx--x u0_a84   u0_a84            2014-10-07 21:42 cache
lrwxrwxrwx install  install           2014-10-07 21:41 lib -> /data/app-lib/com.andqlimax.pushfixer-1
drwxrwx--x u0_a84   u0_a84            2014-10-07 21:42 shared_prefs
-rwxr-xr-x u0_a84   u0_a84     316031 2014-10-07 21:42 sqlite3
root@hammerhead:/data/data/com.andqlimax.pushfixer #

@Chainfire any ideas would be appreciated. I can't figure out what I'm doing wrong.

Apart from your guide, I didn't find to much around and lately I'm not following to much the "root scene" around android L, so maybe I'm missing something.
Thanks for your time
 
Last edited:

Top Liked Posts

  • There are no posts matching your filters.
  • 62
    Guidelines for problem-free su usage

    How-To SU is my guide on using "su" in your own programs (to execute commands as root). The guide covers the major common pitfalls and also provides example code, as I have been asked by several developers to provide.

    I also did a presentation on this stuff at the Big Android BBQ 2012, so if you're looking for the article and code promised there, here it is!

    The text is too long to copy here, but you can find it here:

    http://su.chainfire.eu/

    Example code is located on GitHub:

    https://github.com/Chainfire/libsuperuser

    If you are not an app developer, you have no business posting in this thread. This thread is for developer discussion on the article/example code only. In fact, I do not expect many posts in this thread at all - it's all rather straightforward, and this is not a helpdesk.

    Moderators: Do not move this thread to a development subsection, 0-posters need to be able to reply to it.
    15
    No it isn't acceptable, but the reason is not what you might think.

    Using a generic AsyncTask derived class to run su calls can be a solution. As long as your code ends up running in the background, all is good. However, in my experience what usually happens is that you have to do a lot of things in the background.

    For example, imagine that during your app's startup, you need to check some files, perform some su calls, check some more files, do some computations, etc. Those should all go in a single AsyncTask's doInBackground method. That way you can use onPreExecute and onPostExecute to show and dismiss a dialog that tells the user you are busy.

    Furthermore, if you had 10 su commands to run, would you just call new BackgroundThread ... 10 times? As the call should return before the su command is finished executing, the order of the executions of those commands becomes semi-random, you can't depend on them being run in any specific order, it even differs between Android versions (some versions run AsyncTasks serially, others run X of them in parallel). Not to mention that you shouldn't create 10 separate su processes to run 10 commands unless you have a good reason. Batching commands together == much higher performance.

    The above does depend on which commands you need to execute, the needs of your application, and how you use it. If you only have to execute a single su command, it can be done that way, but I think in general this is not an ideal solution.

    Now, the reason why your solution is truly unacceptable is because you are calling doInBackground. This does not make the code run in the background. You override doInBackground and insert your code, but you call the execute method. You should call your code like this:

    Code:
    new BackgroundThread(command).execute();

    Else you're still calling on the main thread !

    If you really want to keep using this method, keep in mind that you can actually pass parameters to the execute() function that in turn will be passed to doInBackground. Look in the AsyncTask documentation ... :)
    5
    Awesome job man, I definitely learned some new stuff. I've done a little bit differently than your implementation: instead of doing AsyncTask -> run su code inside I did this in my Root class:

    Code:
    class BackgroundThread extends AsyncTask<String, Void, Void> {
    		private String s;
    		public BackgroundThread(String command) {
    			s = command;
    		}
    		@Override
    		protected Void doInBackground(String... command) {
    			Process process = null;
    			DataOutputStream os = null;
    			try {
    				process = Runtime.getRuntime().exec("su");
    				os = new DataOutputStream(process.getOutputStream());
    				os.writeBytes(s+"\n");
    				os.writeBytes("exit\n");
    				os.flush();
    				process.waitFor();
    			} catch (Exception e) {
    			}
    			finally {
    				try {
    					if (os != null)
    						os.close();
    					else
    						process.destroy();
    				} catch (Exception e) {
    
    				}
    			}
    			return null;
    		}
    	}

    And then receive the command in the parameter:

    Code:
    public void run(String command) {
    		new BackgroundThread(command).doInBackground();
    	}

    Is this acceptable from your point of view?
    3
    No it isn't acceptable, but the reason is not what you might think.

    Using a generic AsyncTask derived class to run su calls can be a solution. As long as your code ends up running in the background, all is good. However, in my experience what usually happens is that you have to do a lot of things in the background.

    For example, imagine that during your app's startup, you need to check some files, perform some su calls, check some more files, do some computations, etc. Those should all go in a single AsyncTask's doInBackground method. That way you can use onPreExecute and onPostExecute to show and dismiss a dialog that tells the user you are busy.

    Furthermore, if you had 10 su commands to run, would you just call new BackgroundThread ... 10 times? As the call should return before the su command is finished executing, the order of the executions of those commands becomes semi-random, you can't depend on them being run in any specific order, it even differs between Android versions (some versions run AsyncTasks serially, others run X of them in parallel). Not to mention that you shouldn't create 10 separate su processes to run 10 commands unless you have a good reason. Batching commands together == much higher performance.

    The above does depend on which commands you need to execute, the needs of your application, and how you use it. If you only have to execute a single su command, it can be done that way, but I think in general this is not an ideal solution.

    Now, the reason why your solution is truly unacceptable is because you are calling doInBackground. This does not make the code run in the background. You override doInBackground and insert your code, but you call the execute method. You should call your code like this:

    Code:
    new BackgroundThread(command).execute();

    Else you're still calling on the main thread !

    If you really want to keep using this method, keep in mind that you can actually pass parameters to the execute() function that in turn will be passed to doInBackground. Look in the AsyncTask documentation ... :)

    Hmm... I thought calling new BackgroundThread(command).doInBackground(); was doing it in the background thread... if I call new BackgroundThread(command).execute; the commands won't be called at all until I close the application/activity.

    I don't do X new calls, for example in the BootService I just batch commands together and execute it once.

    I'll use your code and see how it works.
    3
    Lots of 5.0 info added the document.