s3lph
s3lph

Reputation: 4655

Execute ADB command from Java program

The program I'm working on uses ADB (Android Debug Bridge) to send files to my phone:

for (String s : files)
    String cmd = "adb -s 0123456789ABCDEF push " + s + " /mnt/sdcard/" + s;
    try {
        InputStream is = Runtime.getRuntime().exec(cmd).getInputStream();
        while (is.read() != -1) {}
    } catch (IOException e) {
        e.printStackTrace();
    }

I want the program to wait until ADB finished the transmission, but ADB runs as a daemon and therefore never finishes. But the program continues immideately and somehow the files aren't sent to my phone (no exceptions in log). When I run the command from console, it's working without problems.

What am I doing wrong? How do I send files via ADB correctly?

NOTE: the is.read() == -1 won't work, because the ADB daemon writes all output to the system standard output. I've tried forwarding it into a textfile. It stayed empty and the output was still written to the terminal instead

EDIT: Reading the ErrorStream of the ADB process returned the adb help for each adb push-command. Again: The exact commands (copied from Eclipse console) work in a terminal

EDIT 2: Using a ProcessBuilder instead of RUntime.getRuntime.exec() resulted in the following error:

java.io.IOException: Cannot run program "adb -s 0123456789ABCDEF push "inputfile "outputfile""": error=2, File or directory not found

at the ProcessBuilder's start()-method The same happens when using an absolute path for ADB (/usr/bin/adb). The inputfile and outputfile Strings are also absolute paths, like /home/sebastian/testfile and definitely exist. When running the commands from terminal (string "cmd" printed, copy&paste), evreything still works fine.

Upvotes: 8

Views: 40584

Answers (5)

Abdullah Al-Amin
Abdullah Al-Amin

Reputation: 1

Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
string cmd = "/system/bin/input keyevent 23\n";
os.writeBytes(cmd);

the phone must be rooted. here I have executed adb command "input keyevent 23". remember when you execute adb command through su you does not need to add "adb shell input keyevent 23"

Upvotes: 0

Mukesh Rajput
Mukesh Rajput

Reputation: 755

It will be better to give full path for ADB execution: like this $ANDROID_HOME/platform-tools/adb devices

This is the full code you can use:

String cmd = "$ANDROID_HOME/platform-tools/adb devices";
ProcessBuilder processBuilder = new ProcessBuilder();
if (Config.osName.contains("Windows"))
    processBuilder.command("cmd.exe", "/c", cmd);
else
    processBuilder.command("bash", "-c", cmd);

Process process = processBuilder.start();

Upvotes: 0

Harish Gurubatham
Harish Gurubatham

Reputation: 1

 public static void adbpush() {
        System.out.println("adb push....");
        String[] aCommand = new String[] { adbPath, "push", inputFile(String),OutputDirectory };
        try {
            // Process process = new ProcessBuilder(aCommand).start();
            Process process = Runtime.getRuntime().exec(aCommand);
            process.waitFor(3, TimeUnit.SECONDS);
            System.out.println("file pushed");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Upvotes: 0

Sarpe
Sarpe

Reputation: 5806

I've solved in this way:

public class Utils {
    private static final String[] WIN_RUNTIME = { "cmd.exe", "/C" };
    private static final String[] OS_LINUX_RUNTIME = { "/bin/bash", "-l", "-c" };

    private Utils() {
    }

    private static <T> T[] concat(T[] first, T[] second) {
        T[] result = Arrays.copyOf(first, first.length + second.length);
        System.arraycopy(second, 0, result, first.length, second.length);
        return result;
    }

    public static List<String> runProcess(boolean isWin, String... command) {
        System.out.print("command to run: ");
        for (String s : command) {
            System.out.print(s);
        }
        System.out.print("\n");
        String[] allCommand = null;
        try {
            if (isWin) {
                allCommand = concat(WIN_RUNTIME, command);
            } else {
                allCommand = concat(OS_LINUX_RUNTIME, command);
            }
            ProcessBuilder pb = new ProcessBuilder(allCommand);
            pb.redirectErrorStream(true);
            Process p = pb.start();
            p.waitFor();
            BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String _temp = null;
            List<String> line = new ArrayList<String>();
            while ((_temp = in.readLine()) != null) {
                System.out.println("temp line: " + _temp);
                line.add(_temp);
            }
            System.out.println("result after command: " + line);
            return line;

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

If you don't need env variables in your .bash_profile cut "-l" parameter.

I have a Mac but it should work on Linux also.

Upvotes: 11

s3lph
s3lph

Reputation: 4655

I finally got it working:

ProcessBuilder pb = new ProcessBuilder("adb", "-s", "0123456789ABCDEF", "push", inputfile, outputfile);
Process pc = pb.start();
pc.waitFor();
System.out.println("Done");

I don't know what problems ProcessBuilder has with spaces in a string, but finally, it's working...

Upvotes: 11

Related Questions