Runtime.exec() in Android hangs - android

When I try to exec an external script in this way:
try {
process = Runtime.getRuntime().exec(
new String[] { "/system/bin/sh", "./myscript.sh" },
null,
"/data/mydir",
);
} catch (IOException e) {
Log.e(TAG, e.getMessage(), e);
} catch (SecurityException e) {
Log.e(TAG, e.getMessage(), e);
}
Sometimes the script gets executed, but most often my app hangs a couple of seconds until Android says my app is unresponsive and it needs to kill it.
My question is, what may be happening. The script is running sometimes, and there is no exception being thrown, it just hangs. I'm at a loss as to what's happening. I'm using Froyo (2.2.1 I think).
Thanks!

According to the documentation you should read the err and out stream of the process.
http://developer.android.com/reference/java/lang/Process.html
I think something like the following will solve your problem.
class Reader extends Thread
{
InputStream is;
Reader(InputStream is){
this.is = is;
}
public void run()
{
try
{
InputStreamReader inStreamReader = new InputStreamReader(is);
BufferedReader br = new BufferedReader(inStreamReader);
String line=null;
while ( (line = br.readLine()) != null){
// log here
}
} catch (IOException ex){
ex.printStackTrace();
}
}
}
Use the above class in your code like this
try {
process = Runtime.getRuntime().exec(
new String[] { "/system/bin/sh", "./myscript.sh" },
null,
"/data/mydir",
);
Reader err = new Reader(process.getErrorStream());
Reader output = new Reader(process.getInputStream());
err.start();
outout.start();
} catch (IOException e) {
Log.e(TAG, e.getMessage(), e);
} catch (SecurityException e) {
Log.e(TAG, e.getMessage(), e);
} finally {
process.destroy();
}

Related

Android Studio Shell Command From App To Execute [duplicate]

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.

OpenFileInput does NOT throw FileNotFoundException

I'm participating in an online Android course and have (so far) gotten no response on their forum to this issue. I'm using Android Studio on Windows 8.1.
I have the following function to read a file and load an adapter:
private void loadItems() {
BufferedReader reader = null;
try {
FileInputStream fis = openFileInput(FILE_NAME);
reader = new BufferedReader(new InputStreamReader(fis));
String title = null;
String priority = null;
String status = null;
Date date = null;
while (null != (title = reader.readLine())) {
priority = reader.readLine();
status = reader.readLine();
date = ToDoItem.FORMAT.parse(reader.readLine());
mAdapter.add(new ToDoItem(title, Priority.valueOf(priority),
Status.valueOf(status), date));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
} finally {
if (null != reader) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
My questions are:
I don't find the file named by the constant FILE_NAME anywhere on my hard drive. If the file doesn't exist shouldn't openFileInput() throw FileNotFoundException?
Why does InputStreamReader not throw an error?
Via the debugger, I've watched as The logic guarding entry into the WHILE construct happily allows a null value in the title variable to enter the loop. Am I missing something here?
Thanks in advance for any light anyone can shed!!
Markb

Android socket connect freezing

I am trying to implement a simple socket that sends and receives strings from a server.
The following code is freezing the application, not sure if I have done something obviously wrong?
public String internetRoutesRetrieve(String userName) {
String command = null;
String response = null;
Socket socket = null;
DataOutputStream dataOutputStream = null;
DataInputStream dataInputStream = null;
try {
socket = new Socket("Hidden IP", HiddenPort);
dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataInputStream = new DataInputStream(socket.getInputStream());
command = "SEARCH <" + userName + ">";
dataOutputStream.writeUTF(command);
response = dataInputStream.readUTF();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (dataOutputStream != null) {
try {
dataOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (dataInputStream != null) {
try {
dataInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return response;
}
Thanks
Edit: It seems the program is freezing when I am trying to save the response from the server
see AsyncTask for proper client server communication on Android application.
you'd usualy get android.os.NetworkOnMainThreadException if you don't but I'd give it a try.

Android: force a thread to close and display an alert dialog

I have a thread inside which I catch an exception. What I want is that when this happens, the thread closes/quits/dies or whatever I should say, and an alert dialog is displayed (no like toasts!).
Here's my code:
t1 = new Thread(new Runnable()
{
public void run()
{
Looper.prepare();
StringBuffer stringBuffer = new StringBuffer("");
BufferedReader bufferedReader = null;
URI uri = null;
try
{
requestAndMakeSheet(stringBuffer, bufferedReader, uri);
}
catch (Exception e)
{
//Toast.makeText(getBaseContext(), "Web Request Error", Toast.LENGTH_LONG).show();
//Log.e("Web Request Error", e.getMessage());
t1.interrupt();
AlertDialog.Builder parsingErrorBox = new AlertDialog.Builder(ReservationInfo.this);
parsingErrorBox.setTitle("Login error");
parsingErrorBox.setMessage("You may have to check your credentials and then try again.");
parsingErrorBox.show();
}
finally
{
if (bufferedReader!=null)
{
try
{
bufferedReader.close();
}
catch (IOException ioe)
{
Log.e("Web Request Error", ioe.getMessage());
}
}
}
}
});
t1.start();
try
{
t1.join();
mWebview.loadUrl("file:///"+Environment.getExternalStorageDirectory()+"/MySheet.html");
setContentView(mWebview);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
//End of le thread
}
This code crashes, I think it has something to do with t1.interrupt (tried stop instead, but didn't work either).
How can I fix this code?
Thank you in advance.
Why do you have the t1.interrupt() anyway? Seems like your thread will be terminated regardless so what is the reason for putting it there?

Async task, BufferedReader

I have a BufferedReader, when I try to read it, it just hangs and doesn't do anything, am I doing this right? I am using this in an AsyncTask.
Edit: I have a tablet connected to the Wi-Fi, this connects to my computer which is broadcasting on 172.20.104.203 on port 5334, I can see when the thread starts, but nothing after that.
Here my code:
try {
final BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
final String msg;
msg = (line);
Log.d("DeviceActivity", msg);
}
} catch (Exception e) {
e.printStackTrace();
Log.e("ClientAcivtity: Exception",
String.valueOf(e));
}
EDIT
I have all the right permissions or anything, I was doing this outside a AsyncTask and it worked perfectly, moved it because I didn't want it in the main thread.
-Edit , here is the full code.
public class NetworkTask extends AsyncTask<Void, byte[], Boolean> {
Socket nsocket; // Network Socket
InputStream nis; // Network Input Stream
OutputStream nos; // Network Output Stream
private Handler handler = new Handler();
Boolean connected = false;
public static final int PORT = 5334;
public String SERVERIP = "172.20.104.203";
Socket socket;
#Override
protected void onPreExecute() {
Log.i("AsyncTask", "onPreExecute");
InetAddress serverAddr;
try {
serverAddr = InetAddress.getByName(SERVERIP);
socket = new Socket(serverAddr, PORT);
connected = true;
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e("ClientAcivtity: Exception", String.valueOf(e));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e("ClientAcivtity: Exception", String.valueOf(e));
}
}
#Override
protected Boolean doInBackground(Void... params) { // This runs on a
// different thread
boolean result = false;
try {
Log.d("ClientActivity", "C: Connecting...");
if (socket != null) {
int cont = 1;
while (cont == 1) {
try {
Log.d("ClientActivity", "C: Sending command.");
PrintWriter out = new PrintWriter(
new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream())), true);
// where you issue the commands
out.println("getPos");
Log.d("ClientActivity", "C: Sent " + "getPos");
} catch (Exception e) {
Log.e("ClientAcivtity: Exception",
String.valueOf(e));
}
try {
final BufferedReader in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
final String msg;
msg = (line);
Log.d("DeviceActivity", msg);
}
} catch (Exception e) {
e.printStackTrace();
Log.e("ClientAcivtity: Exception",
String.valueOf(e));
}
cont--;
}
Log.d("ClientActivity", "C: Closed.");
}
} catch (Exception e) {
Log.e("ClientAcivtity: Exception", String.valueOf(e));
}
return result;
}
#Override
protected void onProgressUpdate(byte[]... values) {
if (values.length > 0) {
Log.i("AsyncTask", "onProgressUpdate: " + values[0].length
+ " bytes received.");
}
}
#Override
protected void onCancelled() {
Log.i("AsyncTask", "Cancelled.");
}
#Override
protected void onPostExecute(Boolean result) {
if (socket != null) {
if (connected) {
if (result) {
Log.i("AsyncTask",
"onPostExecute: Completed with an Error.");
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
Log.i("AsyncTask", "onPostExecute: Completed.");
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
My guess is that when you write out the command "getPos" the underlying BufferedWriter is not actually sending the data out on the line (you should verify this with tcpdump/wireshark). If this is the case, the server doesn't responsed to the readLine(), since it never got a command. To verify this claim, add out.flush(); after out.println("getPos");
Really, tcpdump will probably give you a better answer then anyone on the forums.
Also see http://developer.android.com/reference/java/io/BufferedWriter.html
Try doing it like this:
final BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
StringBuffer buf = new StringBuffer();
int i;
while((i = in.read()) != -1){
buf.append((char) i);
}
String data = buf.toString();
Reading from sockets is a quite difficult issue depending where the socket is actually connected to and how the other side responds.
If the other side is extremely fast than it can provide the socket with enough data so that the read routines actually work fine. However if there is a delay in the other side of any kind (just needs to be slower than your read routine incl the small default timeout) then your read fails even though there might be data on the other side - just arriving a little too slow at the socket.
Depending on your needs you may wrap your own minimum and maximum timer around the read routine.
Please provide more information and we can better understand the issue.
In many cases it is necessary to have a minimum timeout large enough for the other side to push data to the socket - but you might also need a maximum time for how long you actually want to wait for data to arrive.
UPDATE:
first the runnable to start the monitoring thread. You may use monitoringCanRun in your loop to interrupt the thread if required. And monitoringThreadIsAlive can be used to know if the thread is still running.
monitoringCanRun = true;
new Thread(new Runnable() {
public void run() {
monitoringThreadIsAlive = true;
performMonitoring();
monitoringThreadIsAlive = false;
}
}).start();
}
and performMonitoring looks like:
public void performMonitoring() {
while (monitoringCanRun) {
... do your read in the while loop
...you might like to insert some delay before trying again...
try { //we delay every partial read so we are not too fast for the other side
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

Categories

Resources