[DEV GUIDE][2016.12.22] How-To SU

Search This thread

mikereidis

Inactive Recognized Developer
Jan 28, 2011
7,823
4,146
Ottawa/Gatineau, Canada
/data/data/com.andqlimax.pushfixer/sqlite3: can't execute: Permission denied

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.
 

Chainfire

Moderator Emeritus / Senior Recognized Developer
Oct 2, 2007
11,452
87,862
www.chainfire.eu
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

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.

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.
 
  • Like
Reactions: andQlimax

mikereidis

Inactive Recognized Developer
Jan 28, 2011
7,823
4,146
Ottawa/Gatineau, Canada
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.

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.
 

Chainfire

Moderator Emeritus / Senior Recognized Developer
Oct 2, 2007
11,452
87,862
www.chainfire.eu
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.

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.
 
  • Like
Reactions: mikereidis

andQlimax

Senior Member
Jul 29, 2010
2,562
1,003
Rome
Samsung Galaxy S23 Ultra
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.
Yes, I know that but like chainfire said, switching context should workaround that problem.

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.

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

uio3368

New member
Oct 27, 2014
1
0
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 :(
 

Flyview

Senior Member
May 17, 2010
2,557
1,675
Toronto/San Diego
Hi Chainfire!

I've been using your libsuperuser in my app to run some root commands. For example:

rootCommand(new String[]{
"settings put global airplane_mode_radios " + Settings.Global.RADIO_CELL,
"settings put global airplane_mode_on " + (enabled ? 0 : 1),
"am broadcast -a android.intent.action.AIRPLANE_MODE --ez state " + !enabled});
"settings put global airplane_mode_radios " + originalAirplaneModeRadios});

where rootCommand() is :

public static void rootCommand(final String[] commands) {
new Thread(new Runnable() {

@override
public void run() {
Shell.SU.run(commands);
}
}).start();
}

However, starting on Android Lollipop, it seems like the different commands I'm sending are not executed in order, or at least they are all executed at once, rather than waiting for one to finish before going on to the next. Was this handled differently pre-Lollipop? I am using the v1.60 Oct 10 release of libsuperuser.

Thanks for your awesome work.
 

Chainfire

Moderator Emeritus / Senior Recognized Developer
Oct 2, 2007
11,452
87,862
www.chainfire.eu
Hi Chainfire!

I've been using your libsuperuser in my app to run some root commands. For example:



where rootCommand() is :



However, starting on Android Lollipop, it seems like the different commands I'm sending are not executed in order, or at least they are all executed at once, rather than waiting for one to finish before going on to the next. Was this handled differently pre-Lollipop? I am using the v1.60 Oct 10 release of libsuperuser.

Thanks for your awesome work.

They are executing in order, you're just not executing them in the right context, probably, so SELinux denies these commands. There's a whole section in my document about context switching, check that. You probably want the settings commands to execute as system_app.
 

t1mur

Senior Member
Jan 20, 2013
131
58
timur.mobi
I am running into a sugote issue, like the person with the backup app on the long thread. This happens in my own app, so I can easily reproduce it.
It happens when I call process.waitFor(). The call is followed in logcat with:

Code:
F/libc    (17322): Fatal signal 11 (SIGSEGV), code 1, fault addr 0xb4da21f0 in tid 17366 (Binder_1)
E/DEBUG   (  186): unexpected waitpid response: n=17366, status=00000000
E/        (  186): ptrace detach from 17366 failed: No such process
E/        (  186): debuggerd committing suicide to free the zombie!

The waitFor() won't return and I see a new sugote process eating CPU.
Here the code context (simplified):
Code:
Process proc = exec(new String[]{"su","--context","u:r:system_server:s0"});
DataOutputStream os = new DataOutputStream(proc.getOutputStream());
os.writeBytes("stop adbd\n");
os.flush(); 
os.close();
proc.waitFor();

Interestingly the "stop adbd" command actually works. (It does seem to require system_server.). And when I omit the call to waitFor(), things appear fine. Except for the cpu-eating sugote leftover. I'm using SuperSU 2.16 on Android 5 on a N7 2013.
 
Last edited:

Chainfire

Moderator Emeritus / Senior Recognized Developer
Oct 2, 2007
11,452
87,862
www.chainfire.eu
I am running into a sugote issue, like the person with the backup app on the long thread. This happens in my own app, so I can easily reproduce it.
It happens when I call process.waitFor(). The call is followed in logcat with:

Code:
F/libc    (17322): Fatal signal 11 (SIGSEGV), code 1, fault addr 0xb4da21f0 in tid 17366 (Binder_1)
E/DEBUG   (  186): unexpected waitpid response: n=17366, status=00000000
E/        (  186): ptrace detach from 17366 failed: No such process
E/        (  186): debuggerd committing suicide to free the zombie!

The waitFor() won't return and I see a new sugote process eating CPU.
Here the code context (simplified):
Code:
Process proc = exec(new String[]{"su","--context","u:r:system_server:s0"});
DataOutputStream os = new DataOutputStream(proc.getOutputStream());
os.writeBytes("stop adbd\n");
os.flush(); 
os.close();
proc.waitFor();

Interestingly the "stop adbd" command actually works. (It does seem to require system_server.). And when I omit the call to waitFor(), things appear fine. Except for the cpu-eating sugote leftover. I'm using SuperSU 2.16 on Android 5 on a N7 2013.

The CPU eating should be solved in the next update (I still have to test your example case, but TiBu causing it has been fixed).

What are you basing the above code on, though? Because waitFor() should indeed never return. What you're doing is starting an interactive shell with the su command, then writing the command to stop adbd to it. Instead of closing the shell by issuing an exit command, instead you close the shell's STDIN.

Whether or not a process terminates on closing their STDIN is completely unreliable (though many processes do) and a bad practise in general. Unfortunately, this is a common case among root apps.

If only devs would use one of the several tried and tested libraries instead of insisting on rolling their own methods that invariably fail somewhere.
 

Flyview

Senior Member
May 17, 2010
2,557
1,675
Toronto/San Diego
They are executing in order, you're just not executing them in the right context, probably, so SELinux denies these commands. There's a whole section in my document about context switching, check that. You probably want the settings commands to execute as system_app.
Thanks for the response. I will look into switching context. To get around selinux I had also been calling setenforce 0 and setenforce 1 right before and right after those commands. This is probably terrible practice?

The su commands are definitely getting called successfully, but not reliably, until I separate them with delays. This is why I thought maybe the commands were running out of order, or concurrently.

Sent from my Nexus 5
 
Last edited:

Flyview

Senior Member
May 17, 2010
2,557
1,675
Toronto/San Diego

Understood. I've also seen something strange happen where after running my superuser code, once in a while, the whole system starts crashing. Apps just close, and eventually it gets very slow, logcat can't even keep up with the errors. Then after powering down and back up, apps are "updated" again (re-odexed?). I wonder, is it the same phenomenon that you mention on your site?

All commands that launch Java-based code however must be run as one of the *_app contexts. If you don't, an ART error may be triggered that brings down the entire system. Note that this specific issue does not occur when using Dalvik."
 
Last edited:

Flyview

Senior Member
May 17, 2010
2,557
1,675
Toronto/San Diego
Thanks for the response. I will look into switching context. To get around selinux I had also been calling setenforce 0 and setenforce 1 right before and right after those commands. This is probably terrible practice?

The su commands are definitely getting called successfully, but not reliably, until I separate them with delays. This is why I thought maybe the commands were running out of order, or concurrently.

Sent from my Nexus 5

Understood. I've also seen something strange happen where after running my superuser code, once in a while, the whole system starts crashing. Apps just close, and eventually it gets very slow, logcat can't even keep up with the errors. Then after powering down and back up, apps are "updated" again (re-odexed?). I wonder, is it the same phenomenon that you mention on your site?

I just wanted to update that everything has been working as planned after adding in a su command to switch context to system_app. Thanks Chainfire!
 

Flyview

Senior Member
May 17, 2010
2,557
1,675
Toronto/San Diego
Hi Chainfire,

Please help me with one other thing. I have noticed on Lollipop that after running root commands from my service, the service continues to grow in size at almost 1mB after every call. This was not happening on KitKat. The only thing that has changed is the addition of the context switching command. Am I doing something wrong?

public static void setGpsEnabled(boolean enabled, int originalLocationMode) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
int newSetting = originalLocationMode;
String originalLocationProviders = "network", newLocationProviders = "network";

if (originalLocationMode == Settings.Secure.LOCATION_MODE_HIGH_ACCURACY) { //High accuracy becomes Battery Saving
newSetting = Settings.Secure.LOCATION_MODE_BATTERY_SAVING;
originalLocationProviders = "network,gps";
newLocationProviders = "network";
} else if (originalLocationMode == Settings.Secure.LOCATION_MODE_SENSORS_ONLY) { //Device only becomes Off
newSetting = Settings.Secure.LOCATION_MODE_OFF;
originalLocationProviders = "gps";
newLocationProviders = "off";
}

rootCommand(new String[]{
"su --context u:r:system_app:s0",
"settings put secure location_mode " + (enabled ? originalLocationMode : newSetting),
"settings put secure location_providers_allowed " + (enabled ? originalLocationProviders : newLocationProviders)});

}
}

public static void rootCommand(final String[] commands) {
new Thread(new Runnable() {

@Override
public void run() {
Shell.SU.run(commands);
}
}).start();
}

I got this from Eclipse's Memory Analysis Tool (MAT):

Problem Suspect 2
300 instances of "eu.chainfire.libsuperuser.StreamGobbler", loaded by "dalvik.system.PathClassLoader @ 0x32c83ce0" occupy 7,632,000 (22.00%) bytes.

Keywords
dalvik.system.PathClassLoader @ 0x32c83ce0
eu.chainfire.libsuperuser.StreamGobbler
 
Last edited:

Flyview

Senior Member
May 17, 2010
2,557
1,675
Toronto/San Diego
I've tried to debug what's going on in the Shell.SU.run method. Please see the System.out.println lines I've added. Only the first 1 (TEST1) is reached! It looks to me like proc.waitFor takes forever and the "gobbling" keeps going. This line *is* reached, however, if I do not switch the context to system_app in my root commands that I send.
This is on Android Lollipop, SuperSU 2.27, and the latest libsuperuser.

EDIT: I think I fixed it by running my root commands without "su" before --context u:r:system_app:s0

rootCommand(new String[]{
"--context u:r:system_app:s0",
"settings put secure location_mode " + (enabled ? originalLocationMode : newSetting),
"settings put secure location_providers_allowed " + (enabled ? originalLocationProviders : newLocationProviders)});

}
 
Last edited:

Chainfire

Moderator Emeritus / Senior Recognized Developer
Oct 2, 2007
11,452
87,862
www.chainfire.eu
I've tried to debug what's going on in the Shell.SU.run method. Please see the System.out.println lines I've added. Only the first 1 (TEST1) is reached! It looks to me like proc.waitFor takes forever and the "gobbling" keeps going. This line *is* reached, however, if I do not switch the context to system_app in my root commands that I send.
This is on Android Lollipop, SuperSU 2.27, and the latest libsuperuser.

EDIT: I think I fixed it by running my root commands without "su" before --context u:r:system_app:s0

rootCommand(new String[]{
"--context u:r:system_app:s0",
"settings put secure location_mode " + (enabled ? originalLocationMode : newSetting),
"settings put secure location_providers_allowed " + (enabled ? originalLocationProviders : newLocationProviders)});

}

Code:
Shell.run("su --context u:r:system_app:s0", new String[] {
        "settings put secure location_mode " + (enabled ? originalLocationMode : newSetting),
        "settings put secure location_providers_allowed " + (enabled ? originalLocationProviders : newLocationProviders)
}, null, true);
 
  • Like
Reactions: Flyview

Archipelt

New member
Nov 27, 2014
2
0
I was wondering if the restriction of running binaries outside of the /system partition is lifted by SuperSU? Users report no problems and in my testing all seems well, but can I depend on this to work in the future?

Thanks a lot for your work Chainfire.
 

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.