I am trying to execute a c++ code from java on a remote Windows machine. In order to deal with the remote part, I have created a Web service from where the actual command is run using Runtime.exec(). The c++ exe is not being called directly from the java code. I have a batch file that eventually calls the exe.
The problem is, both java and c++ processes hang. The java code on server side does handle the output stream and error stream. Also, the c++ code is logging everything in a file on Windows. The strange thing is that, when I remove the WS call and run the java code on server side as a standalone java program, it succeeds. Here is the java code:
public class RunCPlusPlusExecutable {
public int runExecutable() {
int exitValue = 0;
try {
Process p = null;
Runtime rt = Runtime.getRuntime();
System.out.println("About to execute" + this + rt);
p = rt.exec("c:/temp/execcplusplus.bat");
System.out.println("Process HashCode=" + p.hashCode());
StreamProcessor errorHandler = new StreamProcessor(p.getErrorStream(), "Error");
StreamProcessor outputHandler = new StreamProcessor(p.getInputStream(), "Output");
errorHandler.start();
outputHandler.start();
exitValue = p.waitFor();
System.out.println("Exit value : " + exitValue);
if (exitValue == 0)
System.out.println("SUCCESS");
else
System.out.println("FAILURE");
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
}
return exitValue;
}
class StreamProcessor extends Thread {
private InputStream is = null;
private String type = null;
private InputStreamReader isr = null;
private BufferedReader br = null;
private FileWriter writer = null;
private BufferedWriter out = null;
StreamProcessor(InputStream is, String type) {
this.is = is;
this.type = type;
}
public void run() {
try {
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
writer = new FileWriter("*******path to log file********");
out = new BufferedWriter(writer);
String line = null;
while ((line = br.readLine()) != null) {
Date date = new Date();
out.write("[" + type + "]: " + date + " : " + line);
out.newLine();
}
writer.flush();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
try {
if (br != null)
br.close();
if (isr != null)
isr.close();
if (out != null)
out.close();
if (writer != null)
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Any idea what is causing the problem and how to debug it? Please note that I won't be able to debug the c++ code.
Thanks
Update 1:
Here are some more details...
The WS server is running from some admin user. And I have been running the standalone java program from some other user.
*It seems that the c++ executable is giving referenced memory error while executing from WS call. There are pop-ups citing the error with OK and Cancel buttons. *
Update 2:
The tomcat server where the WS is deployed is running as a Windows NT service. Can that be the cause of the error? If yes, how to resolve this?
Related
I am new to Android development, and I try to access to the internal terminal (/bin/bash, ...) of Android phone using a java method.
Do you know if such java method exist?
Thanks
You can use Runtime and Process to achieve your task.
private static String executeCommand(String command) {
Process process = null;
BufferedReader reader = null;
String result = "";
try {
String line;
process = Runtime.getRuntime().exec(command);
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((line = reader.readLine()) != null)
result += line + "\n";
} catch (final Exception e) {
e.printStackTrace();
} finally {
try {
if (reader != null)
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (process != null)
process.destroy();
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
}
Where command is any available terminal commands like PING 8.8.8.8
I'm not entirely sure as to what you mean by "accessing the internal terminal". But if you would like to execute commands take a look at the documentation of the Runtime class.
Here's an example on how to use it.
I have a program that loads a text file holding some information and based on that information it runs multiple thread. Each thread is a process. Here is my code:
public class runMultiClient {
public static void main(String[] args){
List<Process> PRlist = new ArrayList<Process>();
List<String[]> commandsList = new ArrayList<String[]>();
boolean running = true;
if (args.length == 2 && args[0].matches("-f")){
String dir = System.getProperty("user.dir");
String path = dir + "/" + args[1];
FileReader fr;
try {
fr = new FileReader(path);
BufferedReader bf = new BufferedReader(fr);
String line = "";
while ((line = bf.readLine()) != null){
String[] tk = line.split(" ");
String[] cmd = {"java", "-jar", "Client.jar", "-a", tk[0], "-p", tk[1],
"-u", tk[2], "-pw", tk[3], "-m", tk[4], "-s", tk[5]};
Process pr = new ProcessBuilder().inheritIO().command(cmd).start();
PRlist.add(pr);
commandsList.add(cmd);
System.out.println(tk[4] + " streaming process is established.");
}
}
catch (FileNotFoundException ex) {ex.printStackTrace();}
catch (IOException ex) {ex.printStackTrace();}
} else {
System.out.println("No stream file was specified.");
}
}}
Inside my Client.jar file, i have a variable that monitors the cpu load of that class:
OperatingSystemMXBean osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class);
cpuLoad = osBean.getProcessCpuLoad();
Is there any way i can reach that variable from the runMultiClient class?
If not, is there any way of using the OperatingSystemMXBean on the running process?
I have tried pr.getClass(), but it got me nowhere.
Any help would be appreciated.
Option #1: Add agent library and expose JMX over HTTP
You can bundle Jolokia agent with your monitored application (another similar thing is SimpleJMX. It exposes JMX beans over http/json so this works for interacting with JMX from other languages like python (and super comfy when troubleshooting from command like). After that you can access mbeans of your interest via apache http client or the like.
Option #2: JMX client
allow remote connections by adding the following params when starting your monitored application:
-Dcom.sun.management.jmxremote.port=9999 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false
Then you should be able to access the mbeans by jconsole and hand written JMX client code, like in the tutorial
Not sure if you need to call ProcessBuilder().inheritIO() for some other requirement, but if not, you could start a daemon thread in your Client.jar process that periodically writes the cpu load to System.out. Then your runMultiClient thread[s] could read those from the InputStream representing the process's System.out. Or, have the thread accept commands and print accordingly. Rough example:
Run this in the spawned Client.jar:
public static void startCmdListener() {
try {
Thread t = new Thread("CmdListener") {
BufferedReader br = null;
InputStreamReader isr = null;
final OperatingSystemMXBean os = (OperatingSystemMXBean) ManagementFactoryHelper.getOperatingSystemMXBean();
public void run() {
try {
isr = new InputStreamReader(System.in);
br = new BufferedReader(isr);
} catch (Exception ex) {
ex.printStackTrace(System.err);
return;
}
try {
String cmd = null;
while(true) {
cmd = br.readLine();
if("cpu".equalsIgnoreCase(cmd)) { // cpu command, print the process load
System.out.println(os.getProcessCpuLoad());
} else if("exit".equalsIgnoreCase(cmd)) { // exit command, break
break;
}
}
} catch (Exception ex) {
ex.printStackTrace(System.err);
return;
}
}
};
t.setDaemon(true);
t.start();
} catch (Exception ex) {
ex.printStackTrace(System.err);
}
}
Run this in the runMultiClient to get the cpu load:
public static double getCpu(OutputStream processIn, InputStream processOut) {
PrintStream ps = null;
BufferedReader br = null;
InputStreamReader isr = null;
try {
ps = new PrintStream(processIn);
isr = new InputStreamReader(processOut);
br = new BufferedReader(isr);
ps.println("cpu");
ps.flush();
return Double.parseDouble(br.readLine());
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
if(ps!=null) try { ps.close(); } catch (Exception x) {}
if(br!=null) try { br.close(); } catch (Exception x) {}
if(isr!=null) try { isr.close(); } catch (Exception x) {}
}
}
In my Java application I am using the exec() command to call a terminal function:
p = Runtime.getRuntime().exec(command);
p.waitFor();
The call uses the zip and unzip calls. Originally I call:
zip -P password -r encrypted.zip folderIWantToZip
When I call the unzip function through java, I specify the password as the method parameter. If the correct password is specified then the call should unzip the encrypted folder:
unzip -P password encrypted.zip
I want a way to find out if the password entered is incorrect. For example, if password is correct, then the call will correctly unzip the zip file. But I notice that no exception is thrown for an incorrect password. How can I determine this?
You could read the process's ErrorStream and InputStream to determine the process output. Sample code given below
public static void main(String[] args) {
try {
String command = "zip -P password -r encrypted.zip folderIWantToZip";
Process p = Runtime.getRuntime().exec(command);
InputStream is = p.getInputStream();
int waitFor = p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = reader.readLine()) != null) {
System.out.println("line:" + line);
}
is = p.getErrorStream();
reader = new BufferedReader(new InputStreamReader(is));
while ((line = reader.readLine()) != null) {
System.out.println("ErrorStream:line: " + line);
}
System.out.println("waitFor:" + waitFor);
System.out.println("exitValue:" + p.exitValue());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
You could use the exitcode to validate the process status as well but it is specific to to program. Normally zero means successfully terminated otherwise abnormal termination.
As per my comment, first thing I would do would be to capture the Process's InputStream and ErrorStream via getInputStream() and getErrorStream(), but especially the latter, the ErrorStream, and check to see what it outputs if the input is in error. Note that these would have to be done in their own thread, else you'll tie up your program. I usually use some type of StreamGobbler class for this. Also, don't ignore the int returned by p.waitFor().
e.g.,
ProcessBuilder pBuilder = new ProcessBuilder(COMMAND);
Process process = null;
try {
process = pBuilder.start();
new Thread(new StreamGobbler("Input", process.getInputStream())).start();
new Thread(new StreamGobbler("Error", process.getErrorStream())).start();
int exitValue = process.waitFor();
System.out.println("Exit Value: " + exitValue);
process.destroy();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (process != null) {
process.destroy();
}
}
And:
class StreamGobbler implements Runnable {
private String name;
private Scanner scanner;
public StreamGobbler(String name, InputStream inputStream) {
this.name = name;
scanner = new Scanner(inputStream);
}
#Override
public void run() {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(name + ": " + line); // or better, log the line
}
scanner.close();
}
}
I have an app which should execute some root commands.
SuperSU version is 1.04.
Su version is 1.02.
Android 4.1.1.
Device is Samsung Galaxy S3 - rooted.
The problem is I cannot get a permission prompt from SuperSU.
I've tried many things, but prompt never shows up.
For RootChecker basic, ADB and other apps it shows up.
Here is my procedure - maybe I'm doing something wrong.
private static String runShellCommand(String command) {
DataOutputStream os = null;
Process process = null;
try {
String [] env = {"PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin"};
process = Runtime.getRuntime().exec("su", env, Environment.getExternalStorageDirectory() );
os = new DataOutputStream(process.getOutputStream());
InputStreamHandler err = new InputStreamHandler(process.getErrorStream(), false);
InputStreamHandler out = new InputStreamHandler(process.getInputStream(), false);
os.writeBytes(command + "\n");
os.flush();
os.writeBytes(EXIT);
os.flush();
os.close();
Log.d(LOGTAG, "Waiting on: " + process.waitFor());
String errOut = err.getOutput();
String stdOut = out.getOutput();
Log.d(LOGTAG, "Exit code: " + process.exitValue());
Log.d(LOGTAG, command + " erroutput: [" + errOut + "]");
Log.d(LOGTAG, command + " output: [" + stdOut + "]");
if (errOut != null && !errOut.equals(""))
return errOut;
else if (stdOut != null&& !stdOut.equals(""))
return stdOut;
else
return null;
} catch (Exception e) {
Log.e(LOGTAG, "runShellCommand error: ", e);
return null;
} finally {
try {
if (os != null) {
os.close();
}
if (process != null) {
Log.d(LOGTAG, "Exit val: " + process.exitValue());
process.destroy();
}
} catch (Exception ignored) {}
}
}
InputStream handler is:
private static class InputStreamHandler extends Thread {
private final InputStream stream;
private final boolean devNull;
StringBuffer output;
public String getOutput() {
return output.toString();
}
InputStreamHandler(InputStream stream, boolean devNull) {
this.devNull = devNull;
this.stream = stream;
output = new StringBuffer();
start();
}
#Override
public void run() {
try {
if (devNull) {
while (stream.read() != -1) {}
} else {
BufferedReader br = new BufferedReader(new InputStreamReader(stream));
while (true) {
String line = br.readLine();
if (line == null) {
Log.d(LOGTAG, "Ended with reading!");
br.close();
return;
}
output.append(line);
}
}
} catch (IOException ignored) {
Log.e(LOGTAG, "Error", ignored);
}
}
}
Anyone have an idea why does it block so it doesn't show permission window?
Thanks.
I'm not exactly sure why this wouldn't work. The first thing that strikes me as odd is passing Environment.getExternalStorageDirectory() to exec. Maybe this (path) is not allowed (to execute from) ?
Why not simply use libsuperuser, written specifically to perform this very task ? It is open source, tiny, fully commented, has an example project, and even a document detailing the common problems you may encounter when trying to do this very operation.
I finally figured it out. The trick is to create a process (execute Runtime.getRuntime().exec("su");) separately in another thread. I'm not sure why this works, but it does.
Similar way is used in RootTools.
This has solved my problem.
I've created a WebApp that relies on external scripts to gather query request by the user (internal software). I've tested, with sucess, the WebApp off the glassfish server provided by netbeans but whenever I try and upload my App to a third party server (Apache Tomcat) I run into the issue of the process.getRuntime exitValue never being written and the WebApp never gets to the result page....
This is the code that I have implemented so far:
Update --> The code now works after reading both stderr and stdin:
pd = new ProcessBuilder("runscript.bat");
pd.redirectErrorStream(true);
process = pd.start();
StreamGobbler inputGobbler = new StreamGobbler(process.getInputStream(), "Input");
StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(),"Error");
errorGobbler.start();
inputGobbler.start();
int exitVal = -1;
try {
exitVal = process.waitFor();
} catch (InterruptedException ex) {
//log Error
}
class StreamGobbler extends Thread {
OutputWriterReader outWR = new OutputWriterReader();
BufferedWriter deadWriter;
InputStream is;
// reads everything from is until empty.
StreamGobbler(InputStream is, String type) {
this.is = is;
createWatch(type);
}
// depending on if Error stream or Input Stream
private void createWatch(String type){
try {
if(type.equals("Error"))
deadWriter = new BufferedWriter(new FileWriter("StdError.txt"));
else if(type.equals("Input"))
deadWriter = new BufferedWriter(new FileWriter("StdInput.txt"));
} catch (IOException ex) {
//log Error
}
}
#Override
public void run() {
try {
InputStreamReader isr = new InputStreamReader(this.is);
BufferedReader br = new BufferedReader(isr);
String line=null;
while ( (line = br.readLine()) != null)
deadWriter.append(line);
deadWriter.flush();
deadWriter.close();
} catch (IOException ioe) {
//log Error
}
}
}
Any Suggerstions? Thanks in advance for any help
The process may not be complete when you call exitValue() on it.
Before process.exitValue() call add:
process.waitFor();