5,597,871 Members 38,766 Now Online
XDA Developers Android and Mobile Development Forum

[2014.01.20][DEV GUIDE] How-To SU

Tip us?
 
Chainfire
Old
(Last edited by Chainfire; 20th January 2014 at 01:43 PM.)
#1  
Chainfire's Avatar
Senior Moderator / Senior Recognized Developer - Where is my shirt? - OP
Thanks Meter 46018
Posts: 8,833
Join Date: Oct 2007

 
DONATE TO ME
Default [2014.01.20][DEV GUIDE] How-To SU

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.
BLOG - G+(Chainfire) - G+(Personal) - TWITTER - IRC - DONATE

A proper quote includes only the relevant paragraphs, and a proper post never ends with the word "why"

Android
HTC G1, Hero, One
Samsung i5800, i9000*2, P1000*2, P7100, i9100*2, N7000, P6800, i9300, N7100, i9505, N9005
Sony T LT30p, Z C6603
Nexus Galaxy*2, N7, N10, N7-2013

SuperSU, Mobile ODIN, TriangleAway, DSLR Controller, CF-Root, 500 Firepaper, OpenDelta, USB Host Diagnostics, ExynosAbuseAPK, Live dmesg+logcat, NoMoarPowah!, CF-Bench, Chainfire3D, CF.lumen, SGS2 SIM Unlocker, GingerBreakAPK, SuperPower, and more!

Windows Mobile 5/6
E-Mobile EM-ONE
HTC Wizard*2, Kaiser, Touch, Diamond, Pro, HD*2, Diamond 2, Pro 2*2, HD2*2
Samsung i780, i900*2, i8000*2, b7300, b7320, b7330, b7620*2, b6520

WMWifiRouter, KaiserTweak, FPUEnabler, WMLongLife, WMRegOptimizer, CFC+GUI, TF3D+v2 ports, Kaiser+Omnia2+Snapdragon 3D drivers, GfxBoost, and more!

Windows Phone 7
LG GW910

NOTICE: I do not respond to tech support questions through PM.
The Following 44 Users Say Thank You to Chainfire For This Useful Post: [ Click to Expand ]
 
franciscofranco
Old
#2  
franciscofranco's Avatar
Recognized Developer
Thanks Meter 80883
Posts: 14,694
Join Date: Dec 2010
Location: Mountain View, CA

 
DONATE TO ME
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?

FacesIn app
Per-App Modes app
Nexus Display Control
franco.Kernel updater Free app
franco.Kernel - Galaxy Nexus
franco.Kernel - Nexus 4
franco.Kernel - Nexus 5
franco.Kernel - Nexus 7
franco.Kernel - Nexus 7 2013
franco.Kernel - Nexus 10


Google+ | Twitter | Portfolio

CruzerLite franco.Kernel case for the Nexus 4
CruzerLite franco.Kernel case for the Galaxy Nexus

You don't like my reply? Read this

However, if you put any trust in Quadrant scores you could use them to prove that dancing naked for 5 minutes in your garden affects device performance. By Chainfire

My applications translations are managed by:

The Following 2 Users Say Thank You to franciscofranco For This Useful Post: [ Click to Expand ]
 
Chainfire
Old
#3  
Chainfire's Avatar
Senior Moderator / Senior Recognized Developer - Where is my shirt? - OP
Thanks Meter 46018
Posts: 8,833
Join Date: Oct 2007

 
DONATE TO ME
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 ...
BLOG - G+(Chainfire) - G+(Personal) - TWITTER - IRC - DONATE

A proper quote includes only the relevant paragraphs, and a proper post never ends with the word "why"

Android
HTC G1, Hero, One
Samsung i5800, i9000*2, P1000*2, P7100, i9100*2, N7000, P6800, i9300, N7100, i9505, N9005
Sony T LT30p, Z C6603
Nexus Galaxy*2, N7, N10, N7-2013

SuperSU, Mobile ODIN, TriangleAway, DSLR Controller, CF-Root, 500 Firepaper, OpenDelta, USB Host Diagnostics, ExynosAbuseAPK, Live dmesg+logcat, NoMoarPowah!, CF-Bench, Chainfire3D, CF.lumen, SGS2 SIM Unlocker, GingerBreakAPK, SuperPower, and more!

Windows Mobile 5/6
E-Mobile EM-ONE
HTC Wizard*2, Kaiser, Touch, Diamond, Pro, HD*2, Diamond 2, Pro 2*2, HD2*2
Samsung i780, i900*2, i8000*2, b7300, b7320, b7330, b7620*2, b6520

WMWifiRouter, KaiserTweak, FPUEnabler, WMLongLife, WMRegOptimizer, CFC+GUI, TF3D+v2 ports, Kaiser+Omnia2+Snapdragon 3D drivers, GfxBoost, and more!

Windows Phone 7
LG GW910

NOTICE: I do not respond to tech support questions through PM.
The Following 7 Users Say Thank You to Chainfire For This Useful Post: [ Click to Expand ]
 
meethere
Old
#4  
meethere's Avatar
Senior Member
Thanks Meter 103
Posts: 707
Join Date: Jan 2012
that's a nice read
thanks for the guide
Get exposure, submit your biz to business web directory
India's Best Online Deals
 
franciscofranco
Old
(Last edited by franciscofranco; 7th November 2012 at 03:26 PM.)
#5  
franciscofranco's Avatar
Recognized Developer
Thanks Meter 80883
Posts: 14,694
Join Date: Dec 2010
Location: Mountain View, CA

 
DONATE TO ME
Quote:
Originally Posted by Chainfire View Post
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.

FacesIn app
Per-App Modes app
Nexus Display Control
franco.Kernel updater Free app
franco.Kernel - Galaxy Nexus
franco.Kernel - Nexus 4
franco.Kernel - Nexus 5
franco.Kernel - Nexus 7
franco.Kernel - Nexus 7 2013
franco.Kernel - Nexus 10


Google+ | Twitter | Portfolio

CruzerLite franco.Kernel case for the Nexus 4
CruzerLite franco.Kernel case for the Galaxy Nexus

You don't like my reply? Read this

However, if you put any trust in Quadrant scores you could use them to prove that dancing naked for 5 minutes in your garden affects device performance. By Chainfire

My applications translations are managed by:

 
pedja1
Old
#6  
pedja1's Avatar
Recognized Developer
Thanks Meter 1366
Posts: 1,181
Join Date: Oct 2011
Location: Zrenjanin

 
DONATE TO ME
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

Sent from my HTC EVO 3D X515m using Tapatalk 2
Device: LG Optimus L9 P760 ROM:CM 10.2, Android 4.3 Recovery: ClockworkMod Touch 6



Kernel Tuner - Take ctrl over your device

Kernel Tuner - Official Website

 
AdamOutler
Old
#7  
AdamOutler's Avatar
Recognized Developer
Thanks Meter 9428
Posts: 5,123
Join Date: Feb 2011
Location: Louisiana

 
DONATE TO ME
I generally work with desktop apps. Is there a reason to not use Runnable?

Code:
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?
Flash with Odin on Windows, Linux and Mac. Use JOdin3, Available in a web browser or offline
Check out my developer pages. Add me to your circles on Google Plus.
 
Chainfire
Old
#8  
Chainfire's Avatar
Senior Moderator / Senior Recognized Developer - Where is my shirt? - OP
Thanks Meter 46018
Posts: 8,833
Join Date: Oct 2007

 
DONATE TO ME
Quote:
Originally Posted by AdamOutler View Post
I generally work with desktop apps. Is there a reason to not use Runnable?

Code:
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?
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.
BLOG - G+(Chainfire) - G+(Personal) - TWITTER - IRC - DONATE

A proper quote includes only the relevant paragraphs, and a proper post never ends with the word "why"

Android
HTC G1, Hero, One
Samsung i5800, i9000*2, P1000*2, P7100, i9100*2, N7000, P6800, i9300, N7100, i9505, N9005
Sony T LT30p, Z C6603
Nexus Galaxy*2, N7, N10, N7-2013

SuperSU, Mobile ODIN, TriangleAway, DSLR Controller, CF-Root, 500 Firepaper, OpenDelta, USB Host Diagnostics, ExynosAbuseAPK, Live dmesg+logcat, NoMoarPowah!, CF-Bench, Chainfire3D, CF.lumen, SGS2 SIM Unlocker, GingerBreakAPK, SuperPower, and more!

Windows Mobile 5/6
E-Mobile EM-ONE
HTC Wizard*2, Kaiser, Touch, Diamond, Pro, HD*2, Diamond 2, Pro 2*2, HD2*2
Samsung i780, i900*2, i8000*2, b7300, b7320, b7330, b7620*2, b6520

WMWifiRouter, KaiserTweak, FPUEnabler, WMLongLife, WMRegOptimizer, CFC+GUI, TF3D+v2 ports, Kaiser+Omnia2+Snapdragon 3D drivers, GfxBoost, and more!

Windows Phone 7
LG GW910

NOTICE: I do not respond to tech support questions through PM.
The Following 2 Users Say Thank You to Chainfire For This Useful Post: [ Click to Expand ]
 
AdamOutler
Old
#9  
AdamOutler's Avatar
Recognized Developer
Thanks Meter 9428
Posts: 5,123
Join Date: Feb 2011
Location: Louisiana

 
DONATE TO ME
Right. I generally launch in a Thread T=new Thread(..). I'be never used AsyncTask. I'm just wondering what its all about.
Flash with Odin on Windows, Linux and Mac. Use JOdin3, Available in a web browser or offline
Check out my developer pages. Add me to your circles on Google Plus.
 
Chainfire
Old
#10  
Chainfire's Avatar
Senior Moderator / Senior Recognized Developer - Where is my shirt? - OP
Thanks Meter 46018
Posts: 8,833
Join Date: Oct 2007

 
DONATE TO ME
Quote:
Originally Posted by AdamOutler View Post
Right. I generally launch in a Thread T=new Thread(..). I'be never used AsyncTask. I'm just wondering what its all about.
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).
BLOG - G+(Chainfire) - G+(Personal) - TWITTER - IRC - DONATE

A proper quote includes only the relevant paragraphs, and a proper post never ends with the word "why"

Android
HTC G1, Hero, One
Samsung i5800, i9000*2, P1000*2, P7100, i9100*2, N7000, P6800, i9300, N7100, i9505, N9005
Sony T LT30p, Z C6603
Nexus Galaxy*2, N7, N10, N7-2013

SuperSU, Mobile ODIN, TriangleAway, DSLR Controller, CF-Root, 500 Firepaper, OpenDelta, USB Host Diagnostics, ExynosAbuseAPK, Live dmesg+logcat, NoMoarPowah!, CF-Bench, Chainfire3D, CF.lumen, SGS2 SIM Unlocker, GingerBreakAPK, SuperPower, and more!

Windows Mobile 5/6
E-Mobile EM-ONE
HTC Wizard*2, Kaiser, Touch, Diamond, Pro, HD*2, Diamond 2, Pro 2*2, HD2*2
Samsung i780, i900*2, i8000*2, b7300, b7320, b7330, b7620*2, b6520

WMWifiRouter, KaiserTweak, FPUEnabler, WMLongLife, WMRegOptimizer, CFC+GUI, TF3D+v2 ports, Kaiser+Omnia2+Snapdragon 3D drivers, GfxBoost, and more!

Windows Phone 7
LG GW910

NOTICE: I do not respond to tech support questions through PM.

The Following 2 Users Say Thank You to Chainfire For This Useful Post: [ Click to Expand ]
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes