execute shell command from android
Asked Answered
C

6

55

I'm trying to execute this command from the application emulator terminal (you can find it in google play) in this app i write su and press enter, so write:

screenrecord --time-limit 10 /sdcard/MyVideo.mp4

and press again enter and start the recording of the screen using the new function of android kitkat.

so, i try to execute the same code from java using this:

Process su = Runtime.getRuntime().exec("su");
Process execute = Runtime.getRuntime().exec("screenrecord --time-limit 10 /sdcard/MyVideo.mp4");

But don't work because the file is not created. obviously i'm running on a rooted device with android kitkat installed. where is the problem? how can i solve? because from terminal emulator works and in Java not?

Codee answered 5/1, 2014 at 9:44 Comment(0)
S
79

You should grab the standard input of the su process just launched and write down the command there, otherwise you are running the commands with the current UID.

Try something like this:

try{
    Process su = Runtime.getRuntime().exec("su");
    DataOutputStream outputStream = new DataOutputStream(su.getOutputStream());

    outputStream.writeBytes("screenrecord --time-limit 10 /sdcard/MyVideo.mp4\n");
    outputStream.flush();

    outputStream.writeBytes("exit\n");
    outputStream.flush();
    su.waitFor();
}catch(IOException e){
    throw new Exception(e);
}catch(InterruptedException e){
    throw new Exception(e);
}
Sodden answered 5/1, 2014 at 9:56 Comment(7)
Some versions of su will take the arguments on the command line, so you could e.g. exec("su -c screenrecord /sdcard/foo.mp4").Gipsy
is it possible to do the recording without root access?Runnels
big thank you for this snippet, and just to add what I missed in this post is that there has to be an \n at the end of the command stringWinola
it has returned below error. Error running exec(). Command: Super User Working Directory: null Environment: nullDiaphoretic
You need to have su in your execution path /system/bin. @HendraTremolant
i run these code and get su error=13, permission denied, does it need root privilege?Wailful
it only works with root access ? does any method work without root ?Lovins
C
35

A modification of the code by @CarloCannas:

public static void sudo(String...strings) {
    try{
        Process su = Runtime.getRuntime().exec("su");
        DataOutputStream outputStream = new DataOutputStream(su.getOutputStream());

        for (String s : strings) {
            outputStream.writeBytes(s+"\n");
            outputStream.flush();
        }

        outputStream.writeBytes("exit\n");
        outputStream.flush();
        try {
            su.waitFor();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        outputStream.close();
    }catch(IOException e){
        e.printStackTrace();
    }
}

(You are welcome to find a better place for outputStream.close())

Usage example:

private static void suMkdirs(String path) {
    if (!new File(path).isDirectory()) {
        sudo("mkdir -p "+path);
    }
}

Update: To get the result (the output to stdout), use:

public static String sudoForResult(String...strings) {
    String res = "";
    DataOutputStream outputStream = null;
    InputStream response = null;
    try{
        Process su = Runtime.getRuntime().exec("su");
        outputStream = new DataOutputStream(su.getOutputStream());
        response = su.getInputStream();

        for (String s : strings) {
            outputStream.writeBytes(s+"\n");
            outputStream.flush();
        }

        outputStream.writeBytes("exit\n");
        outputStream.flush();
        try {
            su.waitFor();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        res = readFully(response);
    } catch (IOException e){
        e.printStackTrace();
    } finally {
        Closer.closeSilently(outputStream, response);
    }
    return res;
}
public static String readFully(InputStream is) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int length = 0;
    while ((length = is.read(buffer)) != -1) {
        baos.write(buffer, 0, length);
    }
    return baos.toString("UTF-8");
}

The utility to silently close a number of Closeables (Soсket may be no Closeable) is:

public class Closer {
// closeAll()
public static void closeSilently(Object... xs) {
    // Note: on Android API levels prior to 19 Socket does not implement Closeable
    for (Object x : xs) {
        if (x != null) {
            try {
                Log.d("closing: "+x);
                if (x instanceof Closeable) {
                    ((Closeable)x).close();
                } else if (x instanceof Socket) {
                    ((Socket)x).close();
                } else if (x instanceof DatagramSocket) {
                    ((DatagramSocket)x).close();
                } else {
                    Log.d("cannot close: "+x);
                    throw new RuntimeException("cannot close "+x);
                }
            } catch (Throwable e) {
                Log.x(e);
            }
        }
    }
}
}
Compellation answered 30/10, 2014 at 13:47 Comment(1)
You sir, rock. Yes.Waki
I
5
Process p;
StringBuffer output = new StringBuffer();
try {
    p = Runtime.getRuntime().exec(params[0]);
    BufferedReader reader = new BufferedReader(
            new InputStreamReader(p.getInputStream()));
    String line = "";
    while ((line = reader.readLine()) != null) {
        output.append(line + "\n");
        p.waitFor();
    }
} 
catch (IOException e) {
    e.printStackTrace();
} catch (InterruptedException e) {
    e.printStackTrace();
}
String response = output.toString();
return response;
Ician answered 11/1, 2015 at 10:19 Comment(1)
I am not able to launch application using above command executer am start -n com.qop.tabletApp.activity.ConfigurationAndSetupAlps
S
0

Late reply, but it will benefit someone. You can use the sh command in the exec() method. Here is my example:

try {
    File workingDirectory = new File(getApplicationContext().getFilesDir().getPath());
    Process shProcess = Runtime.getRuntime().exec("sh", null, workingDirectory);
    try{
        PrintWriter outputExec = new PrintWriter(new OutputStreamWriter(shProcess.getOutputStream()));
        outputExec.println("PATH=$PATH:/data/data/com.bokili.server.nginx/files;export LD_LIBRARY_PATH=/data/data/com.bokili.server.nginx/files;nginx;exit;");
        outputExec.flush();
    } catch(Exception ignored){  }
    shProcess.waitFor();
} catch (IOException ignored) {
} catch (InterruptedException e) {
    try{ Thread.currentThread().interrupt(); }catch(Exception ignored){}
} catch (Exception ignored) { }

What have I done with this? First I call the shell, then I change (set) the necessary environments in it, and finally I start my nginx with it.

This works on unrooted devices too.

Greetings.

Silda answered 12/12, 2022 at 20:51 Comment(0)
T
0

@18446744073709551615's answer is great, but there is a much simpler way to use it if the android phone is rooted with newer version of magisk which is to use --command option to run one time command, this makes the code much simpler and less bug prone

import org.apache.commons.lang3.ArrayUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public static List<String> sudo(String[] cmd) {
        List<String> res = new ArrayList<String>();
        try {
            String[] fullCmd = ArrayUtils.addAll(new String[]{"su", "--command"}, cmd);
            Process su = Runtime.getRuntime().exec(fullCmd);
            BufferedReader stdInput = new BufferedReader(new
                    InputStreamReader(su.getInputStream()));

            BufferedReader stdError = new BufferedReader(new
                    InputStreamReader(su.getErrorStream()));

            String s;
            while ((s = stdInput.readLine()) != null)
                res.add(s);
            while ((s = stdError.readLine()) != null)
                res.add(s);

        } catch (IOException e) {
            e.printStackTrace();
        }
        return res;
}
Teasley answered 25/6, 2023 at 13:40 Comment(0)
I
-1

another solution launch app from android linux shell:

am start -n [your package]/.MainActivity

according Launch an app from Android shell terminal

Ixia answered 22/5, 2023 at 6:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.