My app needs to request SU access (on rooted devices) and the only examples out there say to do this:
Process p = null;
p = Runtime.getRuntime().exec("su");
That's fine, but how do I associate that p process with what I want to do next? For example how do I use that process to open a database so that the attempt to open the database happens with root permissions?
Please see this discussion:
Run secure API calls as root, android
Basically, you'd have to specify the stuff you want to execute in your call to the exec() method. Since that's hard to do, using the system app is really the best way to do things.
For the actual call, do this in your code:
Process p = null;
p = Runtime.getRuntime().exec("su sqlite3 your_query");
Related
Been testing the new Android 6 auto backup/restore function, and run into a problem with my app crashing immediately after a restore. Further investigation revealed that the Application.onCreate() initialization method was not being called before the main Activity.onCreate() method. This strikes me as a likely bug in the new autorestore logic. But I thought I would ask for advice here before reporting it as an official bug.
The sequence of events I go through is
Run the app, always open a main activity window.
Force a backup of app data by entering
adb shell bmgr fullbackup net.anei.cadpage
Use the app manager to force close the app and to clear all app and cache data
Restore app information with
adb shell bmgr restore
Manually launch the app
Resulting logs show that the Activity.onCreate() method is called before the Application.onCreate() is. The app crashes because some critical initialization was not performed by the Application.onCreate() method.
Is there something obvious that I am missing???
FWIW, launching the app a second time after the crash works perfectly.
It's actually intentional, though intrusive.
For full-data backup and restore operations, the package is launched with a base class Application instance, not your manifest-declared subclass. This is because, unfortunately, many apps open files or databases via Application subclasses, and this blocks the ability of the backup machinery to correctly read/write the underlying files. Similarly, your app's content providers are not automatically instantiated for full-data backup/restore operations. The app process is then destroyed following the operation, because of course your app cannot continue to run normally without its expected Application subclass or content providers.
You also don't say exactly what command you're using to perform a test restore, but I suspect you're using the bmgr command with this syntax:
adb shell bmgr restore PACKAGE
This doesn't do what you expect. In particular, it invokes the code path that happens when your app calls BackupManager.requestRestore(observer). In this specific code path, the app is NOT shut down following the restore operation, because the app has asked to observe the operation itself. This means that you're left with the app process still running but with a base class Application. It's a power-user API that is pretty much only safe when the app uses the original key/value backup API. You need to test instead using the other bmgr syntax:
adb shell bmgr restore TOKEN PACKAGE
where TOKEN is the identifier for which dataset should be used. At least on the most recent versions of the OS you can see the current and ancestral dataset tokens in the output of adb shell dumpsys backup.
This all needs to be better documented and made less surprising.
Subclassing Application is generally discouraged; this is one reason. Try to use your own lazy-init statics instead of subclassing Application.
In my app, I have an Activity, which is basically a form for the user to enter data which is then inserted into a database table via a ContentResolver. How do I test this Activity?
My first attempt was to use ActivityInstrumentationTestCase2 which gives me full instrumentation to simulate entering data. However, the underlying ContentProvider is not closed and destroyed between each test, which leaves the database in an unknown state at the beginning of subsequent tests.
My second attempt was to use ActivityUnitTestCase and inject a mock context that can clean up the database for each test. However, this doesn't allow me to enter text or click on buttons in the activity as it is never actually drawn on the test device.
Does anyone have any suggestions about what else I can try?
it seems that what you've been using is intended for library development
You should look at the monkey binary here , which works great for me.
If you're not satisfied with it you could use monkeyRunner which provides more control over the tests you're running.
Edit :
As far as the database testing goes , cant you use the sqlite3 binary for a simple query after each test?
Edit2:
I am thinking of a .sh script that does the following :
Runs monkey for a while - you can specify the number of events for the monkey to send
Invoke sqlite3 with a query that would check the database integrity into a log file (sqlite3 command can take sql query as a second parameter, and you can use ">" to write the output into some file)
Repeat.
There are tons of examples for .sh scripting on the net so you shouldn't have problem with that.
I am assuming you're doing all this in adb shell, but if you're not, make sure to set all your environment variables correctly. Particularly ANDROID_ROOT, ANDROID_ASSETS and ANDROID_DATA should be set to "/system","/system/app" and "/data" accordingly . Also don't forget to "chmod" the .sh file to be executable ( chmod 777 file.sh ).
Another suggestion is to generate and keep track of the monkey random seeds so you can repeat certain inputs that are causing you problems. You can specify a seed with -s parameter.
To run system Command like "ping" in android device , we can use Process to execute them.
I have difficulty in accessing that data which is replied by system for systme commands.
how to set that data in proper format? how to access it and store in different type of variables?
You might want to look at Root Tools - they make it dead simple.
Edit: Ofcourse this works also for non-root commands on non-root devices ... look at getShell(boolean wantRoot)
I assume you executed your command by getting the DataOutputStream for the process. The same way, you can get the command's output by getting the DataInputStream for the same process. However, this will show you all the output. You will have to implement separate logic to parse through this output, make some sense of it and further process it. I suggest you first get the DataInputStream and print out the output, so you get a better idea. There is no easy way to do this, except probably the answer from Eugen Rieck.
On my android app for root user, I perform a shutdown with
su reboot -p
It works ok, but I noticed that the phone is shutdown almost instantly (as opposed from showing the shutdown animation, and probably doing other stuff).
Is this the correct way to shutdown an android phone programmatically? Are there some critical code that requires to be executed before shutdown?
On Android 4.3 or later, there's probably a better way to shut the device down.
Your app doesn't need to be installed as a system app, but it must have root privileges. You can simply run this one command as root in order to shut the device down:
svc power shutdown
I thank Firelord for his answer elsewhere which inspired me to discover the existence of this shell command.
I think this will do a graceful shutdown, but I'm not sure. Maybe it will do an abrupt shutdown. Please test, and then edit this answer to clarify.
Also, the above shell command does not work in Android 4.2.2 or earlier. The help text doesn't mention it. svc rejects the command as invalid and shows some help text in order to try to be helpful.
If your app is rooted, then run the following as root:
am start -a android.intent.action.ACTION_REQUEST_SHUTDOWN
In the Android source code, you can find the following:
/**
* Low-level function turn the device off immediately, without trying
* to be clean. Most people should use
* {#link android.internal.app.ShutdownThread} for a clean shutdown.
*
* #deprecated
* #hide
*/
#Deprecated
public static native void shutdown();
I think that this native function corresponds to your su reboot -p. Moreover, you can see from the quoted code comment that you should use ShutdownThread to do a clean shutdown.
In ShutdownThread, Android does a bunch of things.
It shuts down ActivityManager. I think shutting down ActivityManager means that all activities will pass necessary lifecycle and, thus, the states of activities will be stored. But I'm not sure. I did not check.
Then, Android turns off the cellular radio interface.
After that, it turns off Bluetooth.
Finally, it tries to shut MountService down.
Thus, you can see that it's wrong to do su reboot -p.
See here:
http://developer.android.com/reference/android/os/PowerManager.html
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
pm.reboot("Because I want you to reboot!")
This should work.
I'm developping an app which needs to run a command as root user so I use:
process = Runtime.getRuntime().exec("su");
Then I launch te process with:
os = new DataOutputStream(process.getOutputStream());
os.writeBytes("tcpdump\n");
When I need the process to finish os.writeBytes("exit\n"); doesn't work and process.waitFor(); get's blocked and the process doesn't finish. I need to send Control-C to the process to stop it but I don't know how I could do it.
Thanks.
Find out whether the API has a kill() method somewhere and use that method to send the SIGINT signal to the target process.
On his github, Chainfire provides a sample implementation of a Shell class that you can use to execute commands as root. The class handles all the tasks using Threads so you can be sure that the command will not block even if it does not return.
Code Snippet:
if(Shell.SU.available()){
Shell.SU.run("commandAsRoot"); //Command executed as root
else{
System.out.println("su not found");
Or if you are certain that the su binary is available, you can just run your commands (commented line) and skip the check.
Source: How-To SU
Add this at the location you want a ctrl-c signal to be issued.
Process interrupt = Runtime.getRuntime().exec("su");
ios = new DataOutputStream(interrupt.getOutputStream());
ios.writeBytes("pkill -SIGINT tcpdump");
ios.flush();
ios.close();
interrupt.waitFor();
If there are multiple processes running by the name of tcpdump and you need to be selective, find out the specific process id using pidof and grep commands. Accept the answer if it worked for you. Let me know in comments if you are facing issues.