Using ADB pull command in a Java program - java

I can't get the ADB command to work in Java. The adb command works when inputting it directly to the command line. But when running it in Java, I get error
Cannot run program "adb -s shell": CreateProcess error=2,file not found
What is the proper syntax for running Windows Command line from Java?
The adb command "adb devices" works in the Java application. The command I'm trying to run is "adb pull sdcard/Download/symmetri.txt C:/Users/myUsername/Downloads/Sources", which works in the command prompt, but not from within the Java application. My code is:
public void FilePush() {
try{
String androidFilePath = "sdcard/Download/symmetri.txt ";
String windowsFilePath = "C:\\Users\\myUsername\\Downloads\\Sources\"";
List<String> cmd = new LinkedList<>();
cmd.add("adb -s shell");
cmd.add("adb");
cmd.add("pull");
cmd.add(androidFilePath);
cmd.add(windowsFilePath);
ProcessBuilder builder = new ProcessBuilder(cmd);
builder.redirectErrorStream(true);
Process p = builder.start();
}
catch (IOException e) {
e.printStackTrace();
}
}
I also tried without adb -s shell" and with
String androidFilePath = "\"/storage/sdcard0/Download/symmetri.txt\"";
String windowsFilePath = "\"C:\\Users\\myUsername\\Downloads\\Sources\\"";
But got the same error

Remove the line
cmd.add("adb -s shell");
as you don't want shell but pull.

Thx to the helpful people here, I finally got it to work! I first needed to run adb.exe as a command, before I could run any adb commands. I needed to remove ("adb -s shell") from my list of commands. I was trying to acces a file in the external storage instead of the internal one which needs root access
(Although I have no clue why I can acces the exact same file in a Command prompt window without permitting root acces). If you want to access external files, add root access with
adb root
Full code that works for anyone who might face the same issue :
public void FilePush() {
try{
String androidFilePath = "/storage/emulated/0/Android/data/com.example.myapp/files/myfile.txt";
String windowsFilePath = "C:\\Users\\myUsername\\Downloads\\Sources";
List<String> cmd = new LinkedList<>();
cmd.add("C:\\Users\\myUsername\\AppData\\Local\\Android\\Sdk\\platform-tools\\adb.exe");
cmd.add("pull");
cmd.add(androidFilePath);
cmd.add(windowsFilePath);
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(true);
String line = "null";
pb.redirectErrorStream(true); // can use these 2 line if you want to see output or errors in file.
pb.redirectOutput(new File("C:\\Users\\myUsername\\Downloads\\Sources\\logs.txt"));
Process p = pb.start();
while(p == null)
Thread.sleep(1000);
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
Pattern pattern = Pattern.compile("^([a-zA-Z0-9\\-]+)(\\s+)(device)");
Matcher matcher;
while ((line = in.readLine()) != null) {
if (line.matches(pattern.pattern())) {
matcher = pattern.matcher(line);
if (matcher.find()) ;
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}

Related

How do I run GDB and accept GDB commands through Java output console?

I am trying to build a GUI for GCC which has some basic functionalities like compile, link, execute, debug, etc for C++ programs using Java. I am creating strings of command which I pass to the ProcessBuilder and run it via command prompt and GCC.
command = "cd src & cd Resources & g++ " + compileFile.cpp +" -Wall "+ " -o "+ "tempOut";
This is a sample code for compiling the file.
Part of this is the debug functionality for which I am using GDB. Now the problem is GDB needs additional input to add breakpoints, remove breakpoints and so on. I am having trouble on how to pass these necessary inputs to GDB via Java terminal. If I pass the commands in the command prompt, it is working fine and I get the desired output.
enter image description here
But whenever I fire the GDB command from the Java program, I cannot pass any inputs from the IDE's terminal. I am aware that each GDB command uses a different process and I tried attaching Java's process ID to GDB but I just get a blank output console. It seems that the GDB session has started but there is no way to interact with that process through the IDE's output console.
int pid = Integer.parseInt(ManagementFactory.getRuntimeMXBean().getName().split("#")[0]);
command = "gdb attach "+ pid;
fireCommand();
EDIT
This is the method that interacts with command prompt to take input and display output in the IDE's output console:
public void fireCommand() {
String line;
String os = System.getProperty("os.name");
ProcessBuilder builder;
if(os.startsWith("Win")) {
builder = new ProcessBuilder("cmd.exe", "/c", command);
}
else{
builder = new ProcessBuilder("bash", "-c", command);
}
try {
process = builder.start();
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
while ((line = reader.readLine()) != null) {
if(line.contains("Input the value")) {
//any other user input in non debug execution
String value = JOptionPane.showInputDialog(line);
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(process.getOutputStream()));
writer.write(value, 0, value.length());
writer.newLine();
writer.close();
}
else {
output.append(line).append("\n");
}
}
int exitVal = process.waitFor();
if (exitVal == 0) {
//display("Success!");
display(output.toString());
} else {
String lineErr;
BufferedReader readerErr = new BufferedReader(
new InputStreamReader(process.getErrorStream()));
while ((lineErr = readerErr.readLine()) != null) {
outputErr.append(lineErr).append("\n");
}
//display(exitVal);
display(outputErr.toString()); //Display the uncatched errors
}
} catch (IOException e) {
display("There was a problem with the I/O");
e.printStackTrace();
} catch (InterruptedException e) {
display("There was a interruption with the execution");
e.printStackTrace();
}
if(!outputErr.toString().isEmpty())
errorFormatDisplay(); //display Error output function
}
Any leads on this would be very helpful. Thank you.
I am aware that each GDB command uses a different process
No, gdb runs as one process. Did you mean to say that you are creating a new gdb process every time you try to pass it a gdb command ?
It seems that the GDB session has started but there is no way to interact with that process through the IDE's output console.
Maybe you should use The GDB/MI Interface, which e.g. the Emacs debugger mode gud uses.

Running docker-compose up with ProcessBuilder succeeds, but ProcessBuilder not returning result

I am running docker-compose up with ProcessBuilder and everything works fine in my machine. I am getting the started image details by reading the stream o/p.
Now I have packaged this inside a jar and added to another project as maven dependency. The command works fine, but i am not able to get any details back. ProcessBuilder streams looks empty. But i could see that docker images are running.
I have combined both input and error data. But both are empty.
As a workaround I am running below command,
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}
{{end}}' <<container name>>
in ProcessBuilder , which is working fine if i run directly on a terminal, but that also not returning the IP address.
public List<String> execute(String directory, String command) {
List<String> commands = new ArrayList<>();
commands.add("bash");
commands.add("-c");
commands.add(command);
Process dockerComposeCommand;
ProcessBuilder builder = new ProcessBuilder().inheritIO();
builder.command(commands);
builder.directory(new File(directory).getParentFile());
String path = System.getenv("PATH");
builder.environment().put("PATH","/usr/bin:"+path);
builder.redirectErrorStream(true);
builder.redirectError(ProcessBuilder.Redirect.INHERIT);
List<String> result = new ArrayList<>();
try {
dockerComposeCommand = builder.start();
dockerComposeCommand.waitFor();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(dockerComposeCommand.getInputStream()))) {
String line = reader.readLine();
while (line != null) {
result.add(line);
line = reader.readLine();
}
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
return result;
}
I want to get the details of the containers from ProcessBuilder, which I am getting in my local machine
Got the solution for the same. I just commented inheritIO() as shown below.
ProcessBuilder builder = new ProcessBuilder();//.inheritIO();
One more point is , if you have inheritIO() in your code, the output will be printing in the console of the calling program.
As #DavidMaze mentioned , these ips are of no use. So I have added another method to check the status of docker container.

Run Shell Commands using Java provides problems

public class RunBashCommand {
public synchronized boolean RunInBash(String command) {
System.out.println("CMD: "+command);
/*String s; not working this code also
Process p;
try {
Process p = Runtime.getRuntime().exec(command);
BufferedReader br = new BufferedReader(
new InputStreamReader(p.getInputStream()));
while ((s = br.readLine()) != null)
System.out.println("line: " + s);
p.waitFor();
System.out.println ("exit: " + p.exitValue());
PrintBufferReader(getError(p));
p.destroy();
} catch (Exception e) {
e.printStackTrace();
}*/
try {
Process p = new ProcessBuilder("/bin/sh", command).start();
/*Process p = new ProcessBuilder("/bin/bash", command).start();*/
PrintBufferReader(getError(p));
/*p.destroy();*/
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
private static BufferedReader getOutput(Process p) {
return new BufferedReader(new InputStreamReader(p.getInputStream()));
}
private static BufferedReader getError(Process p) {
return new BufferedReader(new InputStreamReader(p.getErrorStream()));
}
private void PrintBufferReader(BufferedReader br) throws IOException {
int value = 0;
String s = "";
while((value = br.read()) != -1)
{
char c = (char)value;
s = s+c;
}
System.out.println("EEEE: "+s);
}
}
I tried this code, but it did not work.
following output came:
CMD: cd /home/jeevan/workspace/apb_proj/; source init.csh
EEEE: /bin/sh: cd /home/jeevan/workspace/apb_proj/; source init.csh: No such file or directory
CMD: cd /home/jeevan/workspace/apb_proj/verif/compile/; make clean; make compile; make elab
EEEE: /bin/sh: cd /home/jeevan/workspace/apb_proj/verif/compile/; make clean; make compile; make elab: No such file or directory
CMD: sh /home/jeevan/workspace/apb_proj/verif/test_lib/src/apb_test31/runme.csh
EEEE: /bin/sh: sh /home/jeevan/workspace/apb_proj/verif/test_lib/src/apb_test31/runme.csh: No such file or directory
can some one help?
You're effectively running:
/bin/sh "cd /home/jeevan/workspace/apb_proj/; source init.csh"
When you run /bin/sh this way, it treats its first argument as the name of a file to execute as a shell script. Of course, there's no file named "cd /home/jeevan/workspace/apb_proj/; source init.csh", so you get an error message.
The correct way to invoke sh with a command as an argument is like this:
/bin/sh -c "cd /home/jeevan/workspace/apb_proj/; source init.csh"
Using process builder, you'd do:
Process p = new ProcessBuilder("/bin/sh", "-c", command).start();
The next problem that you're likely to run into is that it appears that the command you're trying to invoke is a csh command, not an sh command. "source" is a csh command, and the file you're trying to source is called "init.csh". So maybe you want to invoke csh instead of sh:
Process p = new ProcessBuilder("/bin/csh", "-c", command).start();
You need to split command arguments into separate parameters: not ProcessBuilder("bin/sh", "cd foo/bar") but ProcessBuilder("bin/sh", "cd", "foo/bar").
You can't use shell metacharacters (like ";") too. To run multiple commands, you have to start multiple processes.
Put all your commands into a List and pass it as the argument to the ProcessBuilder. As an alternative you can start the shell process, get it's OutputStream and write commands into this stream to execute them.

Runtime.getRuntime().exec could not execute/show Tabtip.exe

I've set this OnClick method in JavaFX SceneBuilder on a text field that will pop up the Windows 8 touch keyboard if the user select the textfield. However it seems to be nothing happen when I click on the textfield but when I try to check Tabtip.exe in the task manager, it did shown up there. The codes are:
try
{
Runtime rt = Runtime.getRtuntime();
rt.exec( "cmd /c C:\\Programs Files\\Common Files\\Microsoft Shared\\ink\\TabTip.exe");
}
catch
{
ex.printStackTrace();
}
There is not errors triggered or whatsoever, and TabTip.exe is running in task manager, but the pop up keyboard does not show up, anyone has any solution to this? Thanks!
Whenever you want to execute a command which contains spaces in command prompt, you have to wrap it in double quotes.
Like this:
String commandStr = "cmd /c \"C:\\Program Files\\Common Files\\Microsoft Shared\\ink\\mip.exe\"";
rt.exec( commandStr );
And In addition to that, if you want to know your errors, you can get error stream from object of class Process which is returned by runtimeObject.exec().
String commandStr = "cmd /c C:\\Programs Files\\Common Files\\Microsoft Shared\\ink\\TabTip.exe"; // Like you did
InputStream is = rt.exec( commandStr ).getErrorStream();
int b;
while((b=(is.read()))!=-1)
System.out.print((char)b);
}
Please do like this. For me it is ok in window10 with javaFx application.
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "\"C:\\Program Files\\Common Files\\microsoft shared\\ink\\TabTip.exe");
builder.redirectErrorStream(true);
Process p;
try
{
p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while (true)
{
line = r.readLine();
if (line == null)
{
break;
}
System.out.println(line);
}
}
catch (IOException e)`enter code here`
{
// TODO Auto-generated catch block
e.printStackTrace();
}`enter code here`
The only way to run the TabTip.exe is to run the software on Admin mode.
I found the following batch code on the internet.
How to Use On-Screen and Touch Keyboard Instead of Spiral Keyboard
tasklist | find /I "TabTip.exe" >NUL && (taskkill /IM "TabTip.exe" /T)
start "" "TabTip.exe"
That code kills the TabTip process and executes a new TabTip.
In my case, I created a file called keyboard.bat and added the previous example.
In java, I created a method in order to read this file in the same folder.
That is my code
try{
File file = new File("keyboard.bat");
Runtime.getRuntime().exec(file.getAbsolutePath());
}catch(IOException ex){
Logger.getLogger(RunGazePoint.class.getName()).log(Level.SEVERE, null, ex);
}
after that, I compile my app and wrap it in executable mode with launch4j software.
Another way Is to execute by command, If you are using a multithreaded the system can avoid the lecture of file and not execute the software.
create two methods in order to kill and call the keyboard.
//hide the Keyboard
String[] array = new String[]{"cmd.exe","/c","taskkill /IM \"TabTip.exe\" /F\n" +
""};
Runtime.getRuntime().exec(array);
//Show the keyboard
String[] array = new String[]{"cmd.exe","/c","start \"\" \"TabTip.exe\""};
Runtime.getRuntime().exec(array);

how to launch a shell script in a new gnome terminal, from a java program

I'm trying to run a shell script (say myscript.sh) from a java program.
when i run the script from terminal, like this :
./myscript.sh
it works fine.
But when i call it from the java program, with the following code :
try
{
ProcessBuilder pb = new ProcessBuilder("/bin/bash","./myScript.sh",someParam);
pb.environment().put("PATH", "OtherPath");
Process p = pb.start();
InputStreamReader isr = new InputStreamReader(p.getInputStream());
BufferedReader br = new BufferedReader(isr);
String line ;
while((line = br.readLine()) != null)
System.out.println(line);
int exitVal = p.waitFor();
}catch(Exception e)
{ e.printStackTrace(); }
}
It doesnt goes the same way.
Several shell commands (like sed, awk and similar commands) get skipped and donot give any output at all.
Question : Is there some way to launch this script in a new terminal using java.
PS : i've found that "gnome-terminal" command launches a new terminal in shell,
But, i'm unable to figure out, how to use the same in a java code.
i'm quite new to using shell scripting. Please help
Thanks in advance
In java:
import java.lang.Runtime;
class CLI {
public static void main(String args[]) {
String command[] = {"/bin/sh", "-c",
"gnome-terminal --execute ./myscript.sh"};
Runtime rt = Runtime.getRuntime();
try {
rt.exec(command);
} catch(Exception ex) {
// handle ex
}
}
}
And the contents of the script are:
#!/bin/bash
echo 'hello!'
bash
Notes:
You'll do this in a background thread or a worker
The last command, in the shell script, is bash; otherwise execution completes and the terminal is closed.
The shell script is located in the same path as the calling Java class.
Don't overrwrite your entire PATH...
pb.environment().put("PATH", "OtherPath"); // This drops the existing PATH... ouch.
Try this instead
pb.environment().put("PATH", "OtherPath:" + pb.environment().get("PATH"));
Or, use the full directories to your commands in your script file.
You must set your shell script file as executable first and then add the below code,
shellScriptFile.setExecutable(true);
//Running sh file
Process exec = Runtime.getRuntime().exec(PATH_OF_PARENT_FOLDER_OF_SHELL_SCRIPT_FILE+File.separator+shellScriptFile.getName());
byte []buf = new byte[300];
InputStream errorStream = exec.getErrorStream();
errorStream.read(buf);
logger.debug(new String(buf));
int waitFor = exec.waitFor();
if(waitFor==0) {
System.out.println("Shell script executed properly");
}
This worked for me on Ubuntu and Java 8
Process pr =new ProcessBuilder("gnome-terminal", "-e",
"./progrm").directory(new File("/directory/for/the/program/to/be/executed/from")).start();
The previous code creates a new terminal in a specificied directory and executes a command
script.sh Must have executable permissions
public class ShellFileInNewTerminalFromJava {
public static void main(String[] arg) {
try{
Process pr =new ProcessBuilder("gnome-terminal", "-e", "pathToScript/script.sh").start();
}catch(Exception e){
e.printStackTrace();
}
}
}

Categories