I have an android process that I start. It is a getevent command. This (when ran in a console) gives continuous event occurances. I wish to collect these within an Android app. My current way of doing this will effectively collect "one off" process outputs but I can't seem to find a way of storing the continuous results from the getevent method as they occur.
The current code I have for this is the following. It works for things like "ls" but not for continuous streams such as "getevent".
try {
Process chmod = Runtime.getRuntime().exec("getevent -lt /dev/input/event1");
BufferedReader reader = new BufferedReader(new InputStreamReader(chmod.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();
chmod.waitFor();
String outputString = output.toString();
Log.d("output", outputString);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
I had the same issue. Here is how I solved it.
First I created a TimerTask to log/read continuous output in a BufferReader of either a logcat or getevent. TimerTask creates new Thread, which runs in background and doesn't interfere or block other UI handlers in service class. So I believe it is safer that way.
Then I started the TimerTask from Service class in onCreate() method.
One thing is mine device was rooted, so I start with 'su' session. I believe 'sh' session is also works for non root devices.
Service class:
public class ServiceClassPhone extends Service {
....
private GetEventRecorder getEventRecorder;
#Override
public void onCreate() {
....
getEventRecorder= new GetEventRecorder();
getEventRecorder.start();
// (if there is any) postDelay other UI handlers in service
}
And GetEventRecorder class:
public class GetEventRecorder {
....
private static Logger mLogger = new Logger();
private GetEventRecorder mRecorder = null;
Timer timer;
// active su session
private Process mProcess;
// Byte Writer
private OutputStream mStdIn;
private DataOutputStream outputStream;
private BufferedReader br;
{
try {
mProcess = Runtime.getRuntime().exec("su");
outputStream = new DataOutputStream(mProcess.getOutputStream());
String comm1 = "getevent -l";
String comm2 = "logcat -c";
String close = "^C";
String newLine= "\n";
outputStream.writeBytes(comm1);
outputStream.writeBytes(newLine);
} catch (IOException e) {
Log.d(TAG, "Could not spawn su process");
e.printStackTrace();
}
}
public void start() {
try {
timer = new Timer();
timer.scheduleAtFixedRate(new GetEventRecorder.RecorderTask(), 0, 1000);
} catch (Exception e) {
Log.d(TAG, "Exception: " + e);
}
}
public void stop() {
if (mRecorder != null) {
mRecorder.stop();
mRecorder = null;
timer.cancel();
}
}
public void logGetEventData(){
....
}
}
private class RecorderTask extends TimerTask {
public RecorderTask() {}
#Override
public void run() {
try {
String comm1 = "getevent -l";
String comm2 = "logcat -c";
String close = "^C";
byte[] newLine = "\n".getBytes();
outputStream.writeBytes(close);
outputStream.flush();
br = new BufferedReader(new InputStreamReader(mProcess.getInputStream()));
boolean cont=true;
String line;
Log.d(TAG,"geteventLogs BufferedReader for continuous getevent reading... " );
if (br!=null ) {
Log.d(TAG,"geteventLogs BufferedReader is not null checking for readiness... ");
if (br.ready()) {
Log.d(TAG, "BufferedReader for getevent is not null and ready");
String separator = System.getProperty("line.separator");
while ((line = br.readLine()) != null && line.contains("event0:")
&& !line.contains("BufferedReader") ) {
...
logGetEventData();
}catch (Exception e) {
if (DBG) Log.d(TAG, "getevent recorder error: " + e);
}
}
}
}
Related
I have a batch and shell script that execute MYSQL command.
mysql -u user -p < path\etc\script\db\dosomething.sql
I have a java program that uses ProcessBuilder to execute the batch script.
I am aware that this command will prompt the user for the password , I am also aware that I can alternatively use the --password (which throws an unsafe warning) or a config file to set the login parameters.
I want to provide the password using the input prompt via ProcessBuilder but when I run the program it just hangs and I have no idea why.
When I use JVisualVM to view what is happening I notice that the OutputStream thread is not running and if it did then what is hanging the program ? Below is my implementation:-
Class that deals with the InputStream and ErrorStream :
public static class InStream extends Thread {
private final InputStream in;
private final PrintWriter pw;
public InStream(InputStream in, PrintWriter pw, String threadName) {
super(threadName);
this.in = in;
this.pw = pw;
}
#Override
public void run() {
try (BufferedReader br = new BufferedReader(new InputStreamReader(in));) {
String line;
while ((line = br.readLine()) != null) {
if (Thread.currentThread().isInterrupted()) {
Thread.currentThread().interrupt();
break;
}
pw.println(line);
pw.flush();
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
in.close();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}
}
Class that deals with the OutputStream:
public static class OutStream extends Thread {
private final String message;
private final OutputStream out;
public OutStream(OutputStream out, String threadName, String message) {
super(threadName);
this.out = out;
this.message = message;
}
#Override
public void run() {
try (PrintWriter pw = new PrintWriter(out);) {
pw.println(message);
pw.flush();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
Here is the main program:
public static void main(String[] args) {
try {
String password = "Y0urp#ssw0rd";
ProcessBuilder builder = new ProcessBuilder("path\\etc\\script\\cli\\batchWithSQLCommand.bat");
Process process = builder.start();
StringWriter errors = new StringWriter();
StringWriter input = new StringWriter();
new OutStream(process.getOutputStream(), "output-stream-thread", password).start();
new InStream(process.getErrorStream(), new PrintWriter(errors, true), "error-stream-thread").start();
new InStream(process.getInputStream(), new PrintWriter(input, true), "input-stream-thread").start();
process.waitFor();
System.out.println("inputStream: " + input.toString());
System.out.println("Error Stream: " + errors.toString());
} catch (IOException | InterruptedException ex) {
//throw error here
} catch (Error | Exception ex) {
//throw error here
}
}
What could be the problem ?
Referring to
How to add a timeout value when using Java's Runtime.exec()?
But I am always getting worker.exit value NULL so it always throws timeout exception. Below is my code
public class MyClass {
private static class Worker extends Thread {
private final Process process;
private Integer exit;
private Worker(Process process) {
this.process = process;
}
public void run() {
try {
exit = process.waitFor();
} catch (InterruptedException ignore) {
return;
}
}
}
public String run(String command, long replyTimeout) throws Exception {
StringBuffer output = new StringBuffer();
Process p;
p = Runtime.getRuntime().exec(command);
BufferedReader errReader = new BufferedReader(new InputStreamReader(
p.getErrorStream()));
BufferedReader inputReader = new BufferedReader(new InputStreamReader(
p.getInputStream()));
Worker worker = new Worker(p);
worker.start();
try {
worker.join(replyTimeout);
if (worker.exit != null) {
if (worker.exit > 0) {
String line = "";
while ((line = errReader.readLine()) != null) {
output.append(line + "\n");
}
System.out.println(output.toString());
System.out.println(worker.exit);
throw new Exception(output.toString());
} else {
String line = "";
while ((line = inputReader.readLine()) != null) {
output.append(line + "\n");
}
System.out.println(output.toString());
System.out.println(worker.exit);
return output.toString();
}
} else {
throw new TimeoutException();
}
} catch (InterruptedException ex) {
worker.interrupt();
Thread.currentThread().interrupt();
throw ex;
} finally {
p.destroy();
}
}
}
You're doing this all wrong. You have to consume all the output of a process, on both stdout and stderr, before it makes any sense to call waitFor(). Otherwise the process can block trying to write its own output.
NullPointerExceptions on the other hand are just due to trivial coding bugs that you're expected to be able to iron out on your own. At least I expect it.
I am creating a remote-desktop screenshot application. I have two methods on the server 1) To read the Image from client 2) to read the list of task running on the client). But everytime I try to read the client's input stream an EOF excetion is thrown. The stakctrace of the exception is
java.io.EOFException at
java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2323)
at
java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:2792)
at
java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:799)
at java.io.ObjectInputStream.(ObjectInputStream.java:299) at
remoteserverclient.original.ScreenServer$ServerThread.run(ScreenServer.java:254)
Here is the code on the server where the exception is thrown
ObjectInputStream in = new ObjectInputStream(client.getInputStream());
Object obj = in.readObject();
if (obj instanceof Rectangle) {
CaptureScreen(obj, in);
} else if (obj instanceof String) {
CaptureList(in);
}
Here is the complete code for the client
public class ScreenClient {
static Socket server;
public static void main(String[] args) throws Exception {
try {
while (true) {
server = new Socket("localhost", 5494);
BufferedReader bf = new BufferedReader(new InputStreamReader(server.getInputStream()));
String s;
s = bf.readLine();
System.out.println(s);
if (s.contains("execute")) {
new ClientMessageThread().start();
}
if (s.contains("getProcessList")) {
new ClientFetchProcessThread().start();
}
}
} catch (Exception e) {
System.err.println("Disconnected From server ->" + e.getMessage());
}
}
public static class ClientMessageThread extends Thread {
Socket server;
public ClientMessageThread() {
try {
server=new Socket("localhost",5494);
} catch (Exception ex) {
ex.printStackTrace();
}
}
#Override
public void run() {
try {
BufferedImage screen;
Robot robot = new Robot();
Rectangle size = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
screen = robot.createScreenCapture(size);
int[] rgbData = new int[(int) (size.getWidth() * size.getHeight())];
screen.getRGB(0, 0, (int) size.getWidth(), (int) size.getHeight(), rgbData, 0, (int) size.getWidth());
OutputStream baseOut = server.getOutputStream();
ObjectOutputStream out = new ObjectOutputStream(baseOut);
out.writeObject(size);
for (int x = 0; x < rgbData.length; x++) {
out.writeInt(rgbData[x]);
}
out.flush();
server.close();
//added new
} catch (Exception e) {
System.err.println("Disconnected From server ->" + e.getMessage());
}
}
}
public static class ClientFetchProcessThread extends Thread {
Socket server;
public ClientFetchProcessThread() {
try {
server=new Socket("localhost",5494);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void run() {
try {
PrintWriter ps;
System.out.println("\n\n********");
StringBuilder builder = new StringBuilder("");
String query = "tasklist";
Runtime runtime = Runtime.getRuntime();
InputStream input = runtime.exec(query).getInputStream();
BufferedInputStream buffer = new BufferedInputStream(input);
BufferedReader commandResult = new BufferedReader(new InputStreamReader(buffer));
String line = "";
ps = new PrintWriter(server.getOutputStream(), true);
while ((line = commandResult.readLine()) != null) {
builder.append(line + "\n");
//byte[] responseClient=s.getBytes();
ps.write(builder.toString());
System.out.println(builder.toString());
}
server.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
You're both printing and writing objects to port 5494 from the client. The server only reads objects.
Sort it out.
The exception being thrown is EOFException (End of file exception).
ObjectInputStream throws EOFException when it reaches the end of the input. That's standard behaviour. Are you catching all exceptions thrown by in.readObject()?
Documentation:
http://docs.oracle.com/javase/7/docs/api/java/io/ObjectInputStream.html
So I'm starting a Bukkit (Minecraft) server from a GUI.
ProcessBuilder builder = new ProcessBuilder();
builder.redirectErrorStream(true);
builder.command("java", "-jar", file.getAbsolutePath());
try {
p = builder.start();
input = new BufferedReader(new InputStreamReader(p.getInputStream()));
output = new DataOutputStream(p.getOutputStream());
} catch (IOException e) {
Logger.logError(e);
return;
}
There are no errors, and the server itself starts correctly. The input stream works correctly too, as I get all the input as I should. Now, I have this method to send a command to the server.
public void send(String message) {
try {
output.writeUTF(message + "\n");
output.flush();
} catch (IOException e) {
Logger.logError(e);
}
}
For some reason though, it doesn't work. I'm not sure if I missed a step, or am looking over something, etc. Any help would be greatly appreciated!
I suspect the DataOutputStream is writing data in a non-conventional way towards the OutputStream, try using a PrintWriter object instead.
Consider this:
try {
p = builder.start();
input = new BufferedReader(new InputStreamReader(p.getInputStream()));
output = new PrintWriter(p.getOutputStream());
} catch (IOException e) {
Logger.logError(e);
return;
}
The Send method:
public void send(String message) {
output.println(message);
output.flush();
}
P.S You no longer need the try-catch around the output.println() as PrintWriter's print and println methods don't throw IOException.
From bukkit's plugin perspective (read my comment if you have no clue what this is):
final JavaPlugin Inst = ... //This plugin's object
try(BufferedReader Reader = new BufferedReader(new InputStreamReader(System.in, Charset.forName("UTF-8")))){
while((Line = Reader.readLine()) != null){
final String L = Line;
Bukkit.getScheduler().runTask(Inst, new Runnable(){
#Override
public void run() {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), L);
}
});
}
}catch(IOException ex){
//Handle this
}
Here is my sample code, I want to handle the command from standard input while running a new sub process. However, the exec method never returns if I read the system.in. The command in the exec() is very simple and has nothing to do with the stdin.
I'm wondering about is there any way to solve this? How can I start a new sub process while start another thread reading stdin?
public static void main(String[] args){
new Thread(new Runnable(){
public void run(){
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String command = null;
try{
while((command = reader.readLine()) != null){
System.out.println("Command Received:" + command);
}
}catch(Exception ex){
ex.printStackTrace();
//failed to listening command
}
}
}).start();
Process process = null;
try {
process = Runtime.getRuntime().exec("java -cp C:/agenttest Test");
System.out.println("never returns");
process.waitFor();
} catch (IOException e) {
throw new RuntimeException( e );
} catch (InterruptedException e) {
throw new RuntimeException( e );
}
}
The Test class is very simple, here is the Test.java
public static void main(String[] args){
System.out.println("Standard out");
System.out.println("Standard out");
System.err.println("Standard err");
System.out.println("Standard out");
try{
Thread.sleep(10000);
}catch(InterruptedException ex){}
}
The problem could be that you're not handling the error stream and input stream and are overrunning the platform's buffers. Try handling that output as per the famous article, When Runtime.exec() won't.
For example:
import java.io.*;
public class TestMain {
private static final String JAVA_CMD = "java";
private static final String CP = "-cp";
// *** your CLASS_PATH and PROG Strings will of course be different ***
private static final String CLASS_PATH = "C:/Users/hovercraft/Documents/workspace/Yr 2012A/bin";
private static final String PROG = "yr12.m07.b.Test2";
private static final String[] CMD_ARRAY = { JAVA_CMD, CP, CLASS_PATH, PROG };
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
BufferedReader reader = new BufferedReader(new InputStreamReader(
System.in));
String command = null;
try {
while ((command = reader.readLine()) != null) {
System.out.println("Command Received:" + command);
}
} catch (Exception ex) {
ex.printStackTrace();
// failed to listening command
}
}
}).start();
Process process = null;
try {
ProcessBuilder processBuilder = new ProcessBuilder(CMD_ARRAY);
process = processBuilder.start();
InputStream inputStream = process.getInputStream();
setUpStreamGobbler(inputStream, System.out);
InputStream errorStream = process.getErrorStream();
setUpStreamGobbler(errorStream, System.err);
System.out.println("never returns");
process.waitFor();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public static void setUpStreamGobbler(final InputStream is, final PrintStream ps) {
final InputStreamReader streamReader = new InputStreamReader(is);
new Thread(new Runnable() {
public void run() {
BufferedReader br = new BufferedReader(streamReader);
String line = null;
try {
while ((line = br.readLine()) != null) {
ps.println("process stream: " + line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
You should keep reading the input stream, otherwise it will get blocked. It has nothing to do with JVM but the underyling operating system.