Running shell commands from app [Rooted] - android

In my app, I want to run few shell command sand interpret the output. These commands are essentially the on that would run on rooted phone.
How do I do it?

First make sure that the shell command that you need is actually available in Android. I've run into issues by assuming you can do things like redirect output with >.
This method also works on non-rooted phones of I believe v2.2, but you should check the API reference to be sure.
try {
Process chmod = Runtime.getRuntime().exec("/system/bin/chmod 777 " +fileName);
BufferedReader reader = new BufferedReader(
new InputStreamReader(nfiq.getInputStream()));
int read;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
while ((read = reader.read(buffer)) > 0) {
output.append(buffer, 0, read);
}
reader.close();
chmod.waitFor();
outputString = output.toString();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
While it's probably not 100% necessary, it's a good idea to have the process wait for the exec to complete with process.waitFor() since you said that you care about the output.

You need to first ensure you have busybox installed as that would install the list of most commonly used shell commands and then use the following code to run the command.
Runtime.getRuntime().exec("ls");

Related

How to uninstall android system app programmatically?

I can get a list of installed apps (both user and system apps). I am also able to uninstall user apps, however, not able to uninstall system apps.
Is there any way to uninstall system app?
If the phone is already rooted, will the following code work?
Intent intent = new Intent(Intent.ACTION_DELETE);
intent.setData(Uri.parse("package:"+appPackageName.getText().toString()));
context.startActivity(intent);
you can execute root commands with:
runCommand("su");
runCommand("rm /data/system/application.package.apk");
runCommand("rm /data/data/application.package");
//when this doesn´t work try
runCommand("rm -r /data/system/application.package.apk");
runCommand("rm -r /data/data/application.package");
public static void runCommand(String command){
try {
Process chmod = Runtime.getRuntime().exec(command);
BufferedReader reader = new BufferedReader(
new InputStreamReader(chmod.getInputStream()));
int read;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
while ((read = reader.read(buffer)) > 0) {
output.append(buffer, 0, read);
}
reader.close();
chmod.waitFor();
outputString = output.toString();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
There is also a nice library: https://github.com/Free-Software-for-Android/RootCommands
You need to have root access in order to remove system or vendor apps.
$ su
# rm /data/system/application.package.apk
# rm /data/data/application.package
Try this on Rooted Device...it works
Process reboot = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(reboot.getOutputStream());
os.writeBytes("pm uninstall co.example.demo\n");
os.flush();
os.writeBytes("exit\n");
os.flush();
reboot.waitFor();

How do I give superuser access to my app on a device I own and control?

Background
We build and control the hardware devices on which the app will run.
(EDIT)We will build a custom version of the Android OS soon as well.
We're building an app which we expect to be "always-on."
We want the app to be able to self-update, independent of the market. Hence, we are hosting a service which the client app will periodically poll for updates, download the apk, and then install it. Therein lies...
The problem
I want the UpdateService to install the downloaded app update without giving the user the usual permission and update prompts - after all, we control the hardware and the software.
To do that, I think I need to give my app superuser permissions (tho, if there is some other way, then my question becomes something completely different).
But I can't figure out how to do that.
I have read about a superuser app that can be installed - but this seems like a user solution for users who want to root their own phones. Or a solution for devs who want to distribute an app that needs superuser, but they don't control the device on which their users will install it.
Is there a file somewhere in the android OS that lists apps or users which should have su? If so, it's no problem; we control everything.
first I download and then I run the uninstall and install ( the system is rooted)
private void uninstall() {
try {
Process p = Runtime.getRuntime().exec("su");
InputStream es = p.getErrorStream();
DataOutputStream os = new DataOutputStream(p.getOutputStream());
os.writeBytes("pm uninstall com.example.app\n");
os.writeBytes("exit\n");
os.flush();
int read;
byte[] buffer = new byte[4096];
String output = new String();
while ((read = es.read(buffer)) > 0) {
output += new String(buffer, 0, read);
}
p.waitFor();
} catch (Exception e) {
}
}
private void install() {
try {
// Do the magic
Process p = Runtime.getRuntime().exec("su");
InputStream es = p.getErrorStream();
DataOutputStream os = new DataOutputStream(p.getOutputStream());
os.writeBytes("pm install /mnt/sdcard/exampple/app.apk\n");
os.writeBytes("exit\n");
os.flush();
int read;
byte[] buffer = new byte[4096];
String output = new String();
while ((read = es.read(buffer)) > 0) {
output += new String(buffer, 0, read);
}
p.waitFor();
} catch (IOException e) {
Log.d("catch silant", "1");
} catch (InterruptedException e) {
Log.d("catch silant", "2");
}
}
look of this : https://code.google.com/p/auto-update-apk-client/downloads/detail?name=auto-update-apk-client_2012-10-04.tgz&can=2&q=
I think it can help you, I am also trying to do it now if you are success pleas write because I have an hard time with doing it.

Getting output from busybox commands within Android app

For the life of me, I can't get my app to get the response from a process calling busybox from within su shell.
I've tried three different methods, as well as tried a combination of the three to get it to work, but I can never get the output from anything using busybox, only the rest of the commands.
To be more specific, I can get it to return commands like ls /data and cat suchandsuch.file, but anything that starts with "busybox" (i.e. busybox mount, busybox free) just won't show anything.
This was the method that got the closest for me, this code works with ls /data, but not "busybox free"
This one would run the command (for the most part), and return an empty string instead of loop endlessly from the inputstream.
Process p;
try {
p = Runtime.getRuntime().exec(new String[]{"su", "-c", "/system/bin/sh"});
DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
stdin.writeBytes("ls /data\n");
DataInputStream stdout = new DataInputStream(p.getInputStream());
byte[] buffer = new byte[4096];
int read = 0;
String out = new String();
while(true){
read = stdout.read(buffer);
out += new String(buffer, 0, read);
if(read<4096){
break;
}
}
Toast.makeText(getApplicationContext(), out, Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
The toast near the bottom shows everything from ls /data, but when changed to anything for busybox, its blank or null.
I've also tried both of these, but neither of them worked. (I was passing the process to them after the command was run.)
Both of these would always result in the app freezing right when you hit the button for the methods.
String termReader(Process process){
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
try {
int i;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
while ((i = reader.read(buffer)) > 0)
output.append(buffer, 0, i);
reader.close();
return output.toString();
} catch (IOException e) {
e.printStackTrace();
return e.getMessage();
}
}
String processReader(Process process){
InputStream stdout = process.getInputStream();
byte[] buffer = new byte[1024];
int read;
String out = new String();
while(true){
try {
read = stdout.read(buffer);
out += new String(buffer, 0, read);
if(read<1024){
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return out;
}
There's no stack traces to work with, so I'm starting to get a bit stumped.
Edited with the code proposed below, uhm, below :D
I changed it around a small bit to make it a oneclick run thing for easier troubleshooting and testing.
This also freezes when it tries to read the inputstream, and if I call stdin.writeBytes("exit\n") before trying to read the stream it gives me the blank answer from closing the terminal, if I call it after, it loops endlessly.
void Run() {
String command = "busybox traceroute\n";
StringBuffer theRun = null;
try {
Process process = Runtime.getRuntime().exec("su");
DataOutputStream stdin = new DataOutputStream(process.getOutputStream());
stdin.writeBytes(command);
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
int read;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
while ((read = reader.read(buffer)) > 0) {
theRun = output.append(buffer, 0, read);
}
reader.close();
process.waitFor();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Toast.makeText(getApplicationContext(), theRun, Toast.LENGTH_SHORT).show();
}
It seems like its skipping the first line (the busybox info line you get every time you invoke the command) and not catching the rest of the data. Ive tried all variations I can think of to get this working right :/
If anybody's got some insight on this, I'd be greatly appreciative :)
Here is a quick solution... It is a utility class I created just for this. You can use the native shell, a root shell if the device is rooted, or set a custom shell. Here you go.
https://github.com/jjNford/android-shell
I've found a sort of a workaround for this.
First of all, running commands linked to busybox in my case would never return their output through their InputStream, no matter what method I tried (And I tried ALOT lol).
This is what I found out I could do. It's a bit tedious, and doesn't give you the full output, but if you want something to rely on whether a command fired off properly (in my case, my app just wouldn't work right if I couldn't compare how everything ran.)
You cant get the input from the process, but you CAN get the exit value if you work it right :) this works for anything that doesn't give you a complex response (like using cat on a large file)
The difference between the two is easy to find, for instance:
command = "cat /sys" // works, exits with 1
command = "cat /init.rc" doesnt work, exits with 0
This is how I set it up to work easily. Run the commands as normal using the method provided by MasterJB:
process p;
try {
p = Runtime.getRuntime().exec(new String[]{"su", "-c", "/system/bin/sh"});
DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
stdin.writeBytes(command);
stdin.writeBytes("echo $?\n");
DataInputStream stdout = new DataInputStream(p.getInputStream());
byte[] buffer = new byte[4096];
int read = 0;
String out = new String();
while(true){
read = stdout.read(buffer);
out += new String(buffer, 0, read);
if(read<4096){
break;
}
// here is where you catch the error value
int len = out.length();
char suExitValue = out.charAt(len-2);
Toast.makeText(getApplicationContext(), String.valueOf(suExitValue), Toast.LENGTH_SHORT).show();
return0or1(Integer.valueOf(suExitValue), command); // 0 or 1 Method
// end catching exit value
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I also found it easier to make a "0 or 1" method to return what happened. In this example it's fired as a toast. You may also want to test if the char is actually an integer, as some commands give no exit value whatsoever (weird, I know. One instance is ls /sys, this returns a blank exit value when run through a su terminal.)
String return0or1 (int returnValue, String command){
String message = command + " - Cannot get return value.";
if (returnValue == 0){
message = command + " - successful.";
return message;
}
if (returnValue == 1){
message = command + " - failed.";
return message;
}
return message;
}
With a little bit of research you can match just about any exit value with proper responses, just gotta capture them right :)
These methods return just whether the command ran (0), but if it gets a double or triple char exit code, the last digit may be 0 when it failed (i.e. when exit value is 10), so this will work in most cases, but needs to be expanded upon to catch double and triple values.

Syntax for shell command in Android app

I am trying to run
String command = "su -c 'busybox ls /data'";
p = Runtime.getRuntime().exec(command);
in my app, but it seems like the syntax is somehow wrong. I have no problem running it from the terminal emulator app on the phone, though, so I just can't understand why it is not working when called from within my app.
Any help is deeply appreciated!
SOLUTION FOUND! Thanks to the link suggested by onit here. See the code below: for superuser shell commands to work properly, you first need to create a superuser shell and assign it to a process, then write and read on it's input and output streams respectively.
Process p = Runtime.getRuntime().exec(new String[]{"su", "-c", "system/bin/sh"});
DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
//from here all commands are executed with su permissions
stdin.writeBytes("ls /data\n"); // \n executes the command
InputStream stdout = p.getInputStream();
byte[] buffer = new byte[BUFF_LEN];
int read;
String out = new String();
//read method will wait forever if there is nothing in the stream
//so we need to read it in another way than while((read=stdout.read(buffer))>0)
while(true){
read = stdout.read(buffer);
out += new String(buffer, 0, read);
if(read<BUFF_LEN){
//we have read everything
break;
}
}
//do something with the output
Use the function below:
public void shellCommandRunAsRoot(String Command)
{
try
{
Process RunProcess= Runtime.getRuntime().exec("su");
DataOutputStream os;
os = new DataOutputStream(RunProcess.getOutputStream());
os.writeBytes(cmds+"\n");
os.writeBytes("exit+\n");
os.flush();
}
catch (IOException e)
{
// Handle Exception
}
}
Usage:
shellCommandRunAsRoot("pkill firefox");

Run shell commands from android program

This question has been asked here before but the solutions provided are not working..I am trying to display the contents of /data/dalvik-cache folder. I know that to do this we need to become su. I even did that but still i am unable to execute a shell command..
package org.linuxconfidg.Example2;
import android.app.Activity;
import android.widget.*;
import android.os.Bundle;
import java.io.*;
public class Example2Activity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String lsreturn=myFunLs();
TextView tv=new TextView(this);
tv.setText("Hello Sindhu !! Try to get it \n"+lsreturn);
setContentView(tv);
}
public String myFunLs()
{
try {
// Executes the command.
Process process;
process = Runtime.getRuntime().exec("/system/bin/su");
process = Runtime.getRuntime().exec("/system/bin/ls /data/dalvik-cache > /data/local");
pr
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
int read;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
while ((read = reader.read(buffer)) > 0) {
output.append(buffer, 0, read);
}
reader.close();
// Waits for the command to finish.
process.waitFor();
return output.toString();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
Can anyone please help me out in finding out how to run linux commands in android application. I am testing this app in my emulator which is defaultly rooted
You can't simply run 'su' on the emulator, there's no root access by default. You'll need to install the 'su' program as well as the SuperUser.apk, and you'll have to do this each time you start the emulator unless using snapshots.
More information and links to the files you need can be found here on SO as well as this blog post by Russell Davis
I think the problem comes from the fact that you are using TWO different process instances.
You have to be on the su process to carry on sending commands:
You can check the question "Read command output inside su process"
for an answer.
Then I tried & managed to make working code (I'm sure it works!)
public void runAsRoot(String[] cmds) throws Exception {
Process p = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
InputStream is = p.getInputStream();
for (String tmpCmd : cmds) {
os.writeBytes(tmpCmd+"\n");
int readed = 0;
byte[] buff = new byte[4096];
// if cmd requires an output
// due to the blocking behaviour of read(...)
boolean cmdRequiresAnOutput = true;
if (cmdRequiresAnOutput) {
while( is.available() <= 0) {
try { Thread.sleep(200); } catch(Exception ex) {}
}
while( is.available() > 0) {
readed = is.read(buff);
if ( readed <= 0 ) break;
String seg = new String(buff,0,readed);
console.println("#> "+seg);
}
}
}
os.writeBytes("exit\n");
os.flush();
}
In the below example, I try to execute "/system/bin/screencap" to capture android screen.
via adb:
> adb shell
# /system/bin/screencap -p /sdcard/myscreenshot.png
via Android app:
sh = Runtime.getRuntime().exec("su", null,null);
OutputStream os = sh.getOutputStream();
os.write(("/system/bin/screencap -p " + path).getBytes("ASCII"));
os.flush();
os.close();
sh.waitFor();
Hope this helps.

Categories

Resources