i want to show the rules i've created in a textView, using this code;
..................................
public void show(View btn) throws IOException{
Show(tv);
}
public final void Show(TextView tv) throws IOException{
Process Q =Runtime.getRuntime().exec("su -c iptables -L INPUT 1 -n -v --line-numbers ");
String pingResult="";
BufferedReader in = new BufferedReader(new
InputStreamReader(Q.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
tv.setText(pingResult+="\n"+inputLine+"\n");
}
in.close();
}
}
the problem is that it tells me superuser permission granted, but the table doesn't appear in the TextView, even though i've used BufferReader ..... help ?
With this code portion Im doing the same you need but listing a directory and reading the input. Try using this code changing the getRuntime().exec Command.
private String[] GetAppFiles() throws IOException
{
int BUFF_LEN =2048;
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 " + CurrentApkPath + "\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;
}
}
I hope it helps you.
Related
I have successfully compiled the code and generated the executable file. But when i try to execute commands in android application am getting the error iper[1]:syntax error ')' unexpected.Please suggest any solutions. Thanks in advance.
I have done the code execution in an AsyncTask.
#Override
protected String doInBackground(Void... voids) {
//Iperf command syntax check using a Regular expression to protect the system from user exploitation.
String str = inputCommands.getText().toString();
if (!str.matches("(iperf )?((-[s,-server])|(-[c,-client] ([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5]))|(-[c,-client] \\w{1,63})|(-[h,-help]))(( -[f,-format] [bBkKmMgG])|(\\s)|( -[l,-len] \\d{1,5}[KM])|( -[B,-bind] \\w{1,63})|( -[r,-tradeoff])|( -[v,-version])|( -[N,-nodelay])|( -[T,-ttl] \\d{1,8})|( -[U,-single_udp])|( -[d,-dualtest])|( -[w,-window] \\d{1,5}[KM])|( -[n,-num] \\d{1,10}[KM])|( -[p,-port] \\d{1,5})|( -[L,-listenport] \\d{1,5})|( -[t,-time] \\d{1,8})|( -[i,-interval] \\d{1,4})|( -[u,-udp])|( -[b,-bandwidth] \\d{1,20}[bBkKmMgG])|( -[m,-print_mss])|( -[P,-parallel] d{1,2})|( -[M,-mss] d{1,20}))*"))
{
publishProgress("Error: invalid syntax. Please try again.\n\n");
return null;
}
try {
//The user input for the parameters is parsed into a string list as required from the ProcessBuilder Class.
String[] commands = inputCommands.getText().toString().split(" ");
List<String> commandList = new ArrayList<String>(Arrays.asList(commands));
//If the first parameter is "iperf", it is removed
if (commandList.get(0).equals((String) "iperf")) {
commandList.remove(0);
}
//The execution command is added first in the list for the shell interface.
commandList.add(0,"/data/data/com.example.networkcheck/iperf");
//The process is now being run with the verified parameters.
process = new ProcessBuilder().command(commandList).redirectErrorStream(true).start();
//A buffered output of the stdout is being initialized so the iperf output could be displayed on the screen.
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
int read;
//The output text is accumulated into a string buffer and published to the GUI
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
while ((read = reader.read(buffer)) > 0) {
output.append(buffer, 0, read);
//This is used to pass the output to the thread running the GUI, since this is separate thread.
publishProgress(output.toString());
output.delete(0, output.length());
}
reader.close();
process.destroy();
}
catch (IOException e) {
publishProgress("\nError occurred while accessing system resources, please reboot and try again.");
e.printStackTrace();
}
return null;
}
#Override
public void onProgressUpdate(String... strings) {
tv.append(strings[0]);
//The next command is used to roll the text to the bottom
scroller.post(new Runnable() {
public void run() {
scroller.smoothScrollTo(0, tv.getBottom());
}
});
}
TL:DR; version ;)
my app should run without user interaction (autostart etc works)
it should update itself (via apk) without any user interaction
rooted devices are possible
.
problem:
querying a newer apk from a server works
when starting the apk with a (view?) intent, the "install app" prompt pops and needs a user confirmation
How do I solve this without any user interaction?
http://code.google.com/p/auto-update-apk-client/
This seems to be a solution, but there must be better approach.
I already found this: Install Application programmatically on Android
but that doesn't solve my problem.
Solved it! :D
It just works in rooted devices but works perfectly.
Using the unix cmd "pm" (packageManager) allows you to install apks from sdcard, when executing it as root.
Hope this could help some people in the future.
public static void installNewApk()
{
try
{
Runtime.getRuntime().exec(new String[] {"su", "-c", "pm install -r /mnt/internal/Download/fp.apk"});
}
catch (IOException e)
{
System.out.println(e.toString());
System.out.println("no root");
}
}
Required permissions:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
My suggestion is to use plugin mechanism instad of updating the app. You can dynamically load classes from the Web and run them inside your app without any user interaction. There is a lot of resources spread across the Internet:
How to load a Java class dynamically on android/dalvik?
http://android-developers.blogspot.com/2011/07/custom-class-loading-in-dalvik.html
If su -c doesn't work, try su 0 (only rooted devices can do su!)
The full answer looks like this:
private void installNewApk()
{
String path = mContext.getFilesDir().getAbsolutePath() + "/" + LOCAL_FILENAME;
mQuickLog.logD("Install at: " + path);
ProcessUtils.runProcessNoException(mQuickLog, "su", "0", "pm", "install", "-r", path);
}
With this class defined:
public class ProcessUtils {
Process process;
int errCode;
public ProcessUtils(String ...command) throws IOException, InterruptedException{
ProcessBuilder pb = new ProcessBuilder(command);
this.process = pb.start();
this.errCode = this.process.waitFor();
}
public int getErrCode() {
return errCode;
}
public String getOutput() throws IOException {
InputStream inputStream = process.getInputStream();
InputStream errStream = process.getErrorStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
String line;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line + System.getProperty("line.separator"));
}
br = new BufferedReader(new InputStreamReader(errStream));
while ((line = br.readLine()) != null) {
sb.append(line + System.getProperty("line.separator"));
}
return sb.toString();
}
public static String runProcess(String ...command) throws IOException, InterruptedException {
ProcessUtils p = new ProcessUtils(command);
if (p.getErrCode() != 0) {
// err
}
return p.getOutput();
}
public static void runProcessNoException(String ...command) {
try {
runProcess(command);
} catch (InterruptedException | IOException e) {
// err
}
}
}
I am working on a program that needs to be able to determine what is on the android device at Xlocation. I am using "su ls Xlocation"
I want to get back and array list of files but only manage to get back the first Item. Am I missing a command that gets the next line? Or is there something else I need to do.
Below is my command I am sending
String[] commands = new String[]{"ls /system/app/"};
return doCommand(commands);
Below is my current method for doCommand
private boolean doCommand(String[] commands)
{
ArrayList<String> output = new ArrayList<String>();
boolean ran = false;
try
{
Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
DataInputStream ins = new DataInputStream(process.getInputStream());
// This part works I sends the command right!
for (String single : commands)
{
os.writeBytes(single + "\n");
os.flush();
os.writeBytes("exit\n");
os.flush();
process.waitFor();
ran = true;
}
int av = -1;
while (av != 0)
{
//////////////////////////// WORKING ON THIS TO GET ALL INFO /////////////////
av = ins.available();
if (av != 0)
{
byte[] b = new byte[av];
ins.read(b);
output.add(new String(b));
System.out.println(new String(b) + "Recieved form modem");
}
}
}
catch(Exception ex){}
return ran;
}
As seen currently it only returns true or false. However run in debug I only get the first item in output. (output = "[first.apk")
Edited Newer Version;
public ArrayList<String> doCommand(String[] commands)
{
ArrayList<String> output = new ArrayList<String>();
try
{
Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
DataInputStream ins = new DataInputStream(process.getInputStream());
for (String single : commands)
{
os.writeBytes(single + "\n");
//os.flush();
output.add("true");
}
os.writeBytes("exit\n");
byte[] bc = new byte[10000];
String st = "";
while(ins.read(bc) != -1)
{
st += new String(bc);
os.flush();
}
output.add(st);
os.flush();
os.close();
ins.close();
process.waitFor();
}
catch(Exception ex)
{}
return output;
}
Now getting a decent amount of output but still not all where the directory has large items inside size limit of byte[10000] I have checked.
If anyone wants to improve on this and get an exact answer that works do so I still check this post.
Thanks
You can try adapting this method from my open source User Management (GitHub) app to do what you want. This will read each and every line of the output following a terminal command:
public static String[] getUserList()
{
Process p;
try {
p = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
BufferedReader bf = new BufferedReader(new InputStreamReader(p.getInputStream()));
os.writeBytes("pm list-users"+"\n");
os.writeBytes("exit\n");
ArrayList<String> users = new ArrayList<String>();
String test;
bf.readLine();
while((test = bf.readLine()) != null)
{
users.add(test);
}
String[] userList = (String[]) users.toArray(new String[users.size()]);
os.flush();
return userList;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
I'm a bit new to Java but I believe the issue is just a minor oversight.. ne in which I've run into a few times with Python ;)
Because you've added the below into your while loop:
os.writeBytes("exit\n");
os.flush();
After each iteration you are attempting to exit the terminal session. After the first iteration the terminal session would already be closed so this would explain why only the first result would be returned.
I would suggest adding the exit code after the while loop completes to ensure you are not sending the rest of the commands to a dead session. Alternatively you could recreate os during each iteration as well but that seems a bit redundant. ;)
Edit #1
I'm not familiar with the usage of bytes, but I have been able to parse the output of my commands with a similar while loop. I Also added stderr to the input to ensure the buffer is emptied when needed. Upon first glance at your new code, it appears you are defining a new String during each iteration of the while loop, instead of appending the line to a variable. This would cause your variable to be overwritten during each iteration. ;)
Below is some code I've used in the past to accomplish similar tasks. I quickly modified from my source but I am currently unable to give it a test run. Keep in mind that your os
is my stdout, and your ins is my stdin.
Runtime terminal = (Runtime) Runtime.getRuntime();
Process process = terminal.exec("su");
DataOutputStream stdout = new DataOutputStream(process.getOutputStream());
InputStream stderr = process.getErrorStream();
BufferedReader stdin = new BufferedReader(new InputStreamReader(stderr));
String line = "";
String output = "";
// Execute command and flush
stdout.writeBytes("your command here\n");
stdout.flush();
// Append stdin.readLine() to output variable until line is null
while ((line = stdin.readLine()) != null)
output += line;
// I've had mixed luck getting waitFor() to work, but technically it should force
// the shell to wait until the command completes. Uncomment it to try it out.
//process.waitFor();
stdout.writeBytes("exit\n");
stdout.flush();
// Print output to logcat
System.out.println(output);
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.
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.