execute shell command from android - java

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?

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);
}

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);
}
}
}
}
}

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;

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.

Related

Thread won't output stream until it is terminated [duplicate]

This question already has answers here:
Java exec method, how to handle streams correctly
(2 answers)
Closed 3 years ago.
I am trying to print the live output from running an external jar, it runs in a thread and the jar does get executed, the problem is that the output doesnt print until the thread is terminated.
public void run() {
Process proc = null;
try {
proc = Runtime.getRuntime().exec("java -jar A.jar");
InputStream in = proc.getInputStream();
InputStream err = proc.getErrorStream();
BufferedInputStream bis = new BufferedInputStream(in);
BufferedInputStream bes = new BufferedInputStream(err);
String iss = IOUtils.toString(in, "UTF8");
String ess = IOUtils.toString(err, "UTF8");
System.out.println(iss);
System.out.println(ess);
} catch (IOException e) {
e.printStackTrace();
this.interrupt();
}
}
You need to run them both in separate threads, in order to read them simultaneously.
public void run() {
try {
Process proc = Runtime.getRuntime().exec("/home/martin/test.py");
InputStream in = proc.getInputStream();
InputStream err = proc.getErrorStream();
Thread tIn = new Thread(() -> {
try {
while (true) {
int ch;
ch = in.read();
if (ch < 0)
break;
System.out.print((char) ch);
}
} catch (IOException e) {
e.printStackTrace();
}
});
Thread tErr = new Thread(() -> {
try {
while (true) {
int ch;
ch = err.read();
if (ch < 0)
break;
System.err.print((char) ch);
}
} catch (IOException e) {
e.printStackTrace();
}
});
tIn.start();
tErr.start();
try {
tIn.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
tErr.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// this.interrupt();
} catch (IOException e) {
e.printStackTrace();
// this.interrupt();
}
}
That is the quick-and-dirty version in a single function. Of course, it would be preferable to write a class that wraps that functionality.

Automated Telnet client using commons-net

My requirement is to connect to some server through telnet using a java program and run few commands and read the responses. Based on these responses I need to perform some operation
I strated with https://stackoverflow.com/a/1213188/1025328
I'm using commons-net and my program is something like this:
public class TelnetSample {
private TelnetClient telnet;
private InputStream in;
private PrintStream out;
public TelnetSample(String server, int port) {
try {
// Connect to the specified server
telnet = new TelnetClient();
telnet.connect(server, port);
in = telnet.getInputStream();
out = new PrintStream(telnet.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
}
public String readResponse() {
System.out.println("TelnetSample.readResponse()");
StringBuilder out = new StringBuilder();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(out.toString());
System.out.println("==========================================================");
return out.toString();
}
public String read2() {
System.out.println("TelnetSample.read()");
StringBuffer sb = new StringBuffer();
try {
int available = in.available();
for (int index = 0; index < available; index++) {
char ch = (char) in.read();
System.out.print(ch);
sb.append(ch);
}
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
public String sendCommand(String command) {
try {
InputStream is = new ByteArrayInputStream(command.getBytes());
int ch;
while ((ch = is.read()) != -1) {
out.write(ch);
out.flush();
}
System.out.println(command);
String output = read2();
if (output.trim().isEmpty()) {
System.out.println("output empty");
} else {
System.out.println(output);
}
System.out.println("==========================================================");
return output;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void disconnect() {
try {
telnet.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
TelnetSample telnet = new TelnetSample("aspmx2.xxxxxx.com", 25);
telnet.readResponse();
telnet.sendCommand("Helo hi");
telnet.sendCommand("mail from:xyz#testmail.com");
telnet.sendCommand("rcpt to:pk#testmail.com");
telnet.sendCommand("quit");
telnet.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Here apart form the telnet connection response, for every other sendCommand I'm getting an empty response. Can some one point me what could be the issue.
My output is something like this
TelnetSample.readResponse()
220 mx.xxxxxx.com ESMTP o86si4086625pfi.217 - gsmtp
==========================================================
Helo hi
TelnetSample.read()
output empty
==========================================================
mail from:xyz#testmail.com
TelnetSample.read()
output empty
==========================================================
rcpt to:pk#testmail.com
TelnetSample.read()
output empty
==========================================================
quit
TelnetSample.read()
output empty
==========================================================
This code has several issue:
the first issue is in readResponse method. When you use
readLine() you can easy block your code and will wait forever. Please have a look at discussion How to determine the exact state of a BufferedReader?
the second you don't send any CR/LF chars. Server got your requests like a single line. Ex:
mail from:xyz#testmail.comrcpt to:pk#testmail.comquit
To fix first issue you can choose several ways:
use multi-threading model
use NIO API. I would recommend Netty for that. Especially for your case as i can see you didn't use Telnet protocol at all, you connected to SMTP server.
Quick fix but the worst, wait first line from server and go on:
public String readResponse() {
System.out.println("TelnetSmtpSample.readResponse()");
StringBuilder out = new StringBuilder();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
out.append(reader.readLine());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(out.toString());
System.out.println("=====================");
return out.toString();
}
To fix second one:
telnet.sendCommand("Helo hi\r\n");
telnet.sendCommand("mail from:xyz#testmail.com\r\n");
telnet.sendCommand("rcpt to:pk#testmail.com\r\n");
telnet.sendCommand("quit\r\n");
It's possible read2 is getting a null value back from the input stream before data is actually returned. Try something like this:
private String read2() {
StringBuffer sb = new StringBuffer();
try {
do {
if (in.available() > 0) {
char ch = (char) in.read();
sb.append(ch);
} else {
Thread.sleep(1000);
}
} while (in.available()>0);
String output = new String(sb);
return output;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

cannot read all response AT Command

what should i do to read all response from AT Command, i have created one method to send AT Command in class SendAtCommand.java but it always give me some blank result, here is my code:
public String sendCommand(String cmd, CommPortIdentifier portX) throws UnsupportedCommOperationException, IOException, PortInUseException {
String result="kosong";
SerialPort port = null;
try {
port = (SerialPort) portX.open("Wavecom", 5000); // Wait max. 10 sec. to acquire port
} catch (PortInUseException e) {
System.err.println("Port already in use: " + e);
System.exit(0);
}
try {
port.setSerialPortParams(
115200,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
} catch (Exception e) {
System.out.println(e.toString());
}
BufferedReader is = null;
PrintStream os = null;
try {
is = new BufferedReader(new InputStreamReader(port.getInputStream()));
} catch (IOException e) {
System.err.println("Can't open input stream");
is = null;
}
try {
os = new PrintStream(port.getOutputStream(), true);
} catch (IOException e) {
System.err.println("Can't open output stream");
is = null;
}
os.print(cmd);
os.print("\n\r");
String respon;
try {
Thread.sleep(1000);//asal 3000
} catch (InterruptedException ex) {
Logger.getLogger(ThreadConsloe.class.getName()).log(Level.SEVERE, null, ex);
}
try {
while ((respon = is.readLine())!=null) {
result=is.readLine();
try {
Thread.sleep(1500);//asal 3000
} catch (InterruptedException ex) {
Logger.getLogger(ThreadConsloe.class.getName()).log(Level.SEVERE, null, ex);
}
if(result.contains("\n")){
// result.rep
}
System.out.println("result "+result);
}
} catch (IOException e)
{
System.err.println("Can't recieve input signals");
}
port.close();
return result;
}
and i am try to send AT Command using above method like this :
CommPortIdentifier port = CommPortIdentifier.getPortIdentifier("COM15");
SendAtCommand sendX = new SendAtCommand();
String provMenu= sendX.sendCommand("AT+STGI=0", port);
The result (Hyperterminal output) of AT+STGI=0 sholud look like this :
AT+STGI=0
+STGI: "i-SEV Menu"
+STGI: 1,3,"Isi Ulang",0
+STGI: 2,3,"Transfer",0
+STGI: 3,3,"Optional",0
and the result (java output) using my code is :
result
result +STGI: "i-SEV Menu"
result +STGI: 1,3,"Transfer",0
result
result
I assume reason is that you do readLine twice, but print only once. It should be:
while ((result = is.readLine()) != null) {
try {
(reason changed to result variable)

how to run .exe file of a java file in other computers

I have developed a java code in eclipse.My code reads data from a .txt file by using server_ip. I have created an executable jar file of the code and then created an .exe file using launch4j. The .exe file shows data if I run it in my laptop,but it does not show any data if I run it in other pc. then it shows null point exception. my operating system is windows 7-32 bit. I am giving my code here. please give me solutions.
package remotedata;
import java.awt.*;
import java.net.;
import java.io.;
public class remotedataread extends Frame
{
public static void main(String[] args)
throws InterruptedException, IOException{
BufferedReader br = null;
TextArea FileText =
new TextArea(" Content of the File \'temp1.txt\' :");
try
{
URL url =
new URL("file://server_ip/path_file.txt");
InputStream is = url.openStream();
br = new BufferedReader(new InputStreamReader(is));
/* String line = null;
while (true) {
line = br.readLine();
if (line == null) {
//wait until there is more of the file for us to read
Thread.sleep(1000);
}
else {
System.out.println(line);
}
}*/
}
catch (MalformedURLException e)
{
System.out.println("Bad URL");
}
catch (IOException e)
{
System.out.println("IO Error : "+e.getMessage());
}
FileText.setBackground(Color.white);
FileText.append(String.valueOf('\n'));
Frame f = new Frame("server data");
f.setSize(200,200);
f.add(FileText);
f.setVisible(true);
try
{
String s;
s=null;
boolean eof = false;
//while (true) {
s = br.readLine();
System.out.println("Time Temperature");
while( !eof )
{
FileText.append(s + String.valueOf('\n'));
try
{
s = br.readLine();
if ( s == null )
{
// eof = true;
// br.close();
Thread.sleep(1000);
}
else{
//System.out.println("Time Temperature");
System.out.println(s);
}
}
catch (EOFException eo)
{
eof = true;
}
catch (IOException e)
{
System.out.println("IO Error : "+e.getMessage());
}
}
//}
}
catch (IOException e)
{
System.out.println("IO Error : "+e.getMessage());
}
}
}
Maybe , you're application is not able to connect to the other node ..hence its throwing a NullPointer exception .Make sure that computers are in the Network
your prolem seems to be here:
URL url =
new URL("file://server_ip/path_file.txt");
InputStream is = url.openStream();
br = new BufferedReader(new InputStreamReader(is));
the url "file://server_ip/path_file.txt" is valid on your laptop, but not on other pc's

Java - passing input into external C/C++ application

I'm trying to enter some value in external application using Java.
Java application looks like this:
Runtime runtime = Runtime.getRuntime();
// ... str build ...
proc = runtime.exec(str);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
bw.write(value);
bw.flush();
bw.close();
if (proc.waitFor() != 0)
// error msg
// the end
Application hangs at waitFor method.
External application looks like this:
welcome banner
please enter 8 character input:
Welcome banner is printed using printf and input is taken with SetConsoleMode/ReadConsoleInput. ReadConsoleInput reads one char and they are masked with * character.
Help
you can use:
proc.getOutputStream().write("some date".getBytes())
keep in mind that you HAVE to read everything the app send to stdout and stderr, else it might get stuck writing there.
I use a generic class to read it in a different thread.
usage is like:
InputStreamSucker inSucker = new InputStreamSucker(proc.getInputStream());
InputStreamSucker errSucker = new InputStreamSucker(proc.getErrorStream());
proc.waitFor();
int exit = process.exitValue();
inSucker.join();
errSucker.join();
InputStreamSucker code is here:
public class InputStreamSucker extends Thread
{
static Logger logger = Logger.getLogger(InputStreamSucker.class);
private final BufferedInputStream m_in;
private final ByteArrayOutputStream m_out;
private final File m_outFile;
public InputStreamSucker(InputStream in) throws FileNotFoundException
{
this(in, null);
}
public InputStreamSucker(InputStream in, File outFile) throws FileNotFoundException
{
m_in = new BufferedInputStream(in, 4096);
m_outFile = outFile;
m_out = new ByteArrayOutputStream();
start();
}
#Override
public void run()
{
try
{
int c;
while ((c = m_in.read()) != -1)
{
m_out.write(c);
}
}
catch (IOException e)
{
logger.error("Error pumping stream", e);
}
finally
{
if (m_in != null)
{
try
{
m_in.close();
}
catch (IOException e)
{
}
}
try
{
m_out.close();
}
catch (IOException e)
{
logger.error("Error closing out stream", e);
}
if (m_outFile != null)
{
byte data[] = m_out.toByteArray();
if (data.length > 0)
{
FileOutputStream fo = null;
try
{
fo = new FileOutputStream(m_outFile);
fo.write(data);
}
catch (IOException e)
{
logger.error("Error writing " + m_outFile);
}
finally
{
try
{
if (fo != null) fo.close();
}
catch (IOException e)
{
logger.error("Error closing " + m_outFile);
}
}
}
}
}
}
public String getOutput()
{
return new String(m_out.toByteArray());
}
}
Got the answer! The trick is to use WriteConsoleInput() API because program expects keyboard event, not text ... That's why the waitFor() waited forever! :)

Categories