yashsingh1/xdaforums huggingface dataset:
[SuperSU] Chainfire:
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.
[SuperSU] franciscofranco:
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:

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:

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

Is this acceptable from your point of view?
[SuperSU] Chainfire:
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:

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 ... :)
[SuperSU] meethere:
that's a nice read

thanks for the guide
[SuperSU] franciscofranco:
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.
[SuperSU] Deleted member 4303594:
Very nice reading. I always use AsyncTask for su commands, although I learned it the hard way:)

I remember few months back I couldn't figure out why supersu pops up when timeout is at 2-3 seconds:D
[SuperSU] AdamOutler:
I generally work with desktop apps. Is there a reason to not use Runnable?

public void liveBackgroundShellCommand() {

Runnable r = new Runnable() {

public void run() {
boolean LinkLaunched = false;
try {
String[] params = (String[]) Statics.LiveSendCommand.toArray(new String[0]);
Process process = new ProcessBuilder(params).start();
BufferedReader STDOUT = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader STDERR = new BufferedReader(new InputStreamReader(process.getErrorStream()));

This is how I set up a background shell. Then I just pass in the su -c command. Is there a disadvantage to this?
[SuperSU] Chainfire:
If this is about desktop Java, then I don't know. I don't use desktop Java, but in most languages and frameworks it is generally frowning upon to block the UI thread, and the UI thread is usually the main/default/first thread.

If we're talking about Android, then this may be bad, depending on what you are doing. A Runnable by itself says nothing about threading or being in the background, a Runnable is just a generic way to define some code you want to run somewhere, sometime.

The code you pasted here does start the process, but it does not wait for the process to exit or read/write to the streams. As such, this piece of code does not block, and is fine. 9 out of 10 times however, a piece of code like this is going to be followed by something like process.waitFor() or reading from STDOUT/STDERR in which cases it does block, and is thus holding up your UI thread and thus bad.

Furthermore, as detailed in the article, calling "su -c" can be errorprone.
[SuperSU] AdamOutler:
Right. I generally launch in a Thread T=new Thread(..). I'be never used AsyncTask. I'm just wondering what its all about.
[SuperSU] Chainfire:
Ok, yeah that's fine. AsyncTask is pretty much a Thread wrapper with handy utility functions (onPreExecute, onPostExecute, onProgressUpdate) that is specifically aimed at running a short-lived task away from the UI thread, often with UI feedback (it's brilliant for use with progress dialogs, for example).
[SuperSU] AdamOutler:
Ah ha! its like a SwingWorker() but with better functionality... Thanks Chainfire! I just looked and apparently it's not available on desktop or I would be switching immediately. That's a wonderful class.
[SuperSU] mikereidis:
Great & sorely needed topic, thank you. I rarely check this forum, but stumbled in here. Hopefully busy devs of SU apps will be pointed here by someone.

I continue to have lots of problems with SuperUser/SuperSU apps that seem to be pre-configured or something to prevent SU access; and the user is never even prompted. But I don't think this is being discussed here.

At some point in the early development of ICS ROMs I noted that SU calls were taking much longer, perhaps about 0.1 seconds. So I optimized the 4-5 seconds and 40 or 50 calls (including blind chmod's for files that didn't exist on many devices) to about 2-4 calls for most devices.

I know I continue to be guilty of calling SU, and shell, and various other things from improper places, such as UI threads, onCreate etc. But I don't think these cause too much trouble in general, so putting these in threads or wherever is an exercise I save for an app re-design.

My app currently allows selection of "SU Type", but it doesn't seem to be needed anymore, now that I'm avoiding the quoting problems I've had previously.

I use the system() call from C/JNI in a lib. My best/default is like this, where CMD is the command, and noting that \" is " escaped in C:

system ("echo \"CMD\" | su -c sh");

This works, but writes to the filesystem every time:

system ("su -c \"sh /data/local/cmd\""); // Write CMD to cmd file first.

The simplest, but I was having more problems with this for whatever reason; perhaps quoting issues:

system ("su -c \"CMD\"");
[SuperSU] pisy3:
thx

---------- Post added at 11:03 PM ---------- Previous post was at 10:58 PM ----------

it is great
[SuperSU] andrewpmoore:
I'm trying to convert my app to use your example classes for running root commands, as most of my app was implemented ok, but I needed to change a couple of bits based on your document. Once chaning I keep running into the following error:

11-20 22:16:39.770: I/System(31924): libcore.io.ErrnoException: kill failed: ESRCH (No such process)

11-20 22:16:39.770: I/System(31924):	at libcore.io.Posix.kill(Native Method)

11-20 22:16:39.770: I/System(31924):	at libcore.io.ForwardingOs.kill(ForwardingOs.java:77)

11-20 22:16:39.770: I/System(31924):	at java.lang.ProcessManager$ProcessImpl.destroy(ProcessManager.java:257)

11-20 22:16:39.770: I/System(31924):	at eu.chainfire.libsuperuser.Shell.run(Shell.java:100)

11-20 22:16:39.770: I/System(31924):	at eu.chainfire.libsuperuser.Shell$SH.run(Shell.java:149)

11-20 22:16:39.770: I/System(31924):	at com.rageconsulting.android.lightflow.util.RootUtil.runRootUnixCommand(RootUtil.java:49)

I'm calling my own helper method which is just a wrapper around your Shell class and it's getting called from an IntentService so I'm not quite sure why this happens.
[SuperSU] Dark3n:
You can ignore that.

By calling exit here, the process is usually gone.

When it tries to destroy the process in this line, the process is already gone, so it throws that error message as there is nothing to kill/destroy.

Before Android 4.0 this message was not even printed into the log.
[SuperSU] Chainfire:
Update the library code with some changes (like proper gobbling). See GitHub :)
[SuperSU] maluus:
Hello dear developers of the supersu. first thanks for good work. I don't know if anyone informed but after htc one s jb update there seem to be some compatibility problems.
[SuperSU] Chainfire:
The article has been updated to v1.20.

Changes are clearly marked in the "Table of Contents"

http://su.chainfire.eu/
[SuperSU] mcnamaragio:
Does the library support other superuser apps too?
[SuperSU] Chainfire:
Yes, it's all about best practises when calling the su binary - it should work with all superuser apps.
[SuperSU] mcnamaragio:
At Supporting multiple icons in your app you mention you plan to write a blog post about changing application theme and locale at runtime. Do you still plan to publish it ? I am very interested in those techniques.
[SuperSU] Chainfire:
If I ever have the time for it :)
[SuperSU] Xuuuud:
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?
[SuperSU] windflyer:
I am curious why you said "ProcessBuilder does not work consistently across all Android versions", any evidence or reference?

Thanks.
[SuperSU] Chainfire:
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.
[SuperSU] windflyer:
Thanks for you reply. Actually, I have not met any open-source android apps that use ProcessBuilder yet.
[SuperSU] GENiALi:
OnCommandResultListener bevor all OnSTDOUTLineListener liOnCommandResultLnes are send

Hi

I will use ping with libsuperuser. I use this 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?
[SuperSU] Chainfire:
Attach the OnCommandResultListener to the addCommand call instead
[SuperSU] GENiALi:
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
[SuperSU] Chainfire:
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.
[SuperSU] GENiALi:
ok, i search another solution.:o
[SuperSU] Burn02:
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:

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.
[SuperSU] Burn02:
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!!!

And it works!!! :)
[SuperSU] Chainfire:
The guide has been updated to revision 1.40, adding information about SELinux/SEAndroid and some upcoming drama from Android 4.5
[SuperSU] mikereidis:
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.
[SuperSU] Chainfire:
Guide updated to v1.50 with even more new things about SELinux and the upcoming Android release - How-To SU.

Also be sure to check out my G+ post about the subject here: https://plus.google.com/+Chainfire/posts/ZtXAhw164QD
[SuperSU] wtfrtfmdiy:
command hangs

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
[SuperSU] andQlimax:
Hi [MENTION=631273]Chainfire[/MENTION]

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:

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:

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
[SuperSU] Chainfire:
Check logcat and/or audit logs to see what exactly has been blocked, is the place to start.
[SuperSU] andQlimax:
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:

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

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 #

[MENTION=631273]Chainfire[/MENTION] 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
[SuperSU] mikereidis:
Android L does not allow executing binaries from the /data partition .

You have to remount /system as RW and copy it to /system/bin or another /system directory.

This works on the Android L preview. On some Android L releases to come, you may not be able to remount /system and will have to copy files from recovery.
[SuperSU] Chainfire:
Latest AOSP and L preview are odd ducks out. My How-To SU guide describes how to get around the issue by switch for example to the system_server or system_app contexts, to be able to execute apps from /data. See the --context parameter of su.

However, to be perfectly honest, if you're not done yet porting to L preview, I'd hold off until L retail is released (which should be in a few weeks), and then wait for the first SuperSU release after that. The latest SuperSU beta versions already have a new way of patching into these new builds that may take care of the bulk of the issues (such as the one you are having) for most root apps. These are not 100% complete solutions for all apps, but it goes a loooong way. The question is if this method will still work on L retail. But if it does, it will all be backported down to 4.2.2, so all SELinux enforcing Android roots will behave the same again. So right now, all is pretty much in limbo. There are some tricky ways to get things to work, but in a few weeks all may be a significantly easier, so spending too much time on it now would be a waste.
[SuperSU] mikereidis:
I figure the "writing is on the wall" regarding Android security getting tighter and tighter as time goes forward. When chmod is insufficient to get app process access to /dev/snd/*. /dev/ttyHS0. /dev/radio0 etc. I have to try a new approach.

So I've re-architected my root radio app to do all SU/root stuff from a daemon lauched with SU. This has benefits for speed and minimizing bugs and fancy code too. I'm guessing this will fix some Knox issues too.

Having a few months of warning was a welcome move by Google. But I think there will be a constant stream of security tightening ahead and sometimes drastic re-architectures are needed.
[SuperSU] Chainfire:
Well, if you have a Nexus device, building AOSP from source today will pretty much show you what security will be like on L retail. It is indeed significantly tighter than L preview.
[SuperSU] andQlimax:
Yes, I know that but like chainfire said, switching context should workaround that problem.

I'm already using context parameter, I tried switching to almost all contexts in your guide ( not sure, will check again) , but always get the same error.

I will do some other tests and maybe I will also follow your advise to wait couple weeks and see how things evolve.

Thanks for your time and work ;)
[SuperSU] uio3368:
i've read your blog "How-To SU", the libsuperuser_example app didn't work in my Nexus 7. Should i replace the origin su binary with ChainsDD's su binary? But i need to root. Did i make something wrong? Please hlp :(