run external commands from java(Android) and read continuous output - android

I want to run excutable such as ping(or any other which gives continuous output) and read its output and print it in my GUI.
I used following method to run my commands:
command=Runtime.getRuntime().exec("ping www.google.com");
and I am reading the output as following:
BufferedReader in = new BufferedReader(new InputStreamReader(command.getInputStream()));
while ((line = in.readLine()) != null) {
System.out.println(line+"\n");
}
this works fine , although display output pretty late compared to time taken when i execute ./excutable using adb -d shell.
As I want to this output(line) in gui so I make a TextView and append the output(line) in it as:
txtview=(TextView)findViewById(R.id.textview);
while ((line = in.readLine()) != null) {
txtview.append(line+"\n");
System.out.println(line+"\n");
}
but this crashes my application.
please tell me how to get over this problem.

If your last block of code is being executed in an Activity, then you are probably blocking the UI thread for too long. This will cause Android to force close your application. Try using AsyncTask to get the output and update your GUI.

Related

Android running su within app

When I use adb to access my device (Android 4.4.2 straight from the manufactures with their custom rom - its not a regular device - it has built in 2D barcode scanner) it goes straight to having a # which I've read means I have root access. And if I run "id" I get the following:
uid=0(root) gid=0(root) context=u:r:adbd:s0
However, when I run "su" from within my app and then "id" I get the following:
uid=10079(u0_a79) gid=10079(u0_a79) groups=50079(all_a79) context=u:r:untrusted_app:s0n
So it's clearly not running as root.
Is my understanding all wrong, in believing that it should be running as root from within the app, or is there something else I need to do in order to get this working?
Any advice would be much appreciated.
Here is the code I'm currently using to run the su and id commands:
p = Runtime.getRuntime().exec("su");
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "n");
}
p = Runtime.getRuntime().exec("id");
p.waitFor();
reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "n");
}
One other thing I forgot to mention - I copy the app to /system/priv-app and run it from there. Still no luck.
I had a Chinese tablet with problem like that. Just re-root it (replace su binary). Should work.
P.S. Seeing any code would also help.
There is an android manifest permission you can use to gain root access
<uses-permission android:name="android.permission.FACTORY_TEST" />
Your app will run as a manufacturer test application, running as the root user. Thus making the 'su' command accessible to your app.
However, I doubt that Google Play will allow you to upload in store with such permission.

Run uiautomator in Runtime.getRuntime().exec() does not give real time status

In my uiautomator script, i will send some interim status. When i run the uiautomator from command prompt using adb, i can see my status print outs one at a time. But when i run it with code snippet as below, i dont get it one at a time. I will only get the whole big chunk of status all at once after the test finish. I need to get the status in real time manner for some parsing.
It looks to me like the output is buffered and flushed at once. I've tried to change the buffer size of the BufferedReader but still not working as how it looks like when running from command prompt.
Anyone has any idea?
String tempString;
Process process = Runtime.getRuntime().exec("uiautomator runtest DummyUiAutomation.jar -c com.dummy.DummyAutomation#DummyAction");
BufferedReader buffReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((tempString = buffReader.readLine()) != null) {
//do some parsing
}
Have you tried to use Process.waitFor() after reading the stream?
String tempString;
Process process = Runtime.getRuntime().exec("uiautomator runtest DummyUiAutomation.jar -c com.dummy.DummyAutomation#DummyAction");
BufferedReader buffReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((tempString = buffReader.readLine()) != null) {
//do some parsing
}
process.waitFor();
From docs:
Causes the current thread to wait, if necessary, until the process
represented by this Process object has terminated. This method returns
immediately if the subprocess has already terminated. If the
subprocess has not yet terminated, the calling thread will be blocked
until the subprocess exits.

Problems clearing logcat

I'm using the Android's log to supervise an application use, so I'm using logcat into the phone not in Eclipse.
Well, if I just write in the log and send me the information everything it's ok, but I receive information from previous executions.
I decided to clear the log every time that my application starts, but now I usually lose the first log messages. Maybe logcat needs some time to get cleared? because when I try to do into debug everything it's ok.
Example:
clear log, message 1, message 2, message 3, ...
Sometimes I don't receive message 1, sometimes don't receive 1 and 2...
I have checked all my code for possible accidental clears but I didn't find anything...
I call this function at the beginning (in onCreate())
public static void clearLog(){
ArrayList<String> commandLine = new ArrayList<String>();
commandLine.add("logcat");
commandLine.add("-c");//CLEAR
Runtime process = Runtime.getRuntime();
process.exec(commandLine.toArray(new String[0]));
TAG = "";
}
Then I add logs
log.i(TAG, "message1");
..
log.i(TAG, "messageN");
And this is how I collect the log:
ArrayList<String> commandLine = new ArrayList<String>();
commandLine.add("logcat");
commandLine.add("-d");//dump and exit
commandLine.add("-v");//especify verbose mode
commandLine.add("raw");//raw show only the message, brief for show all
commandLine.add(TAG + ":V");//show TAG's log
commandLine.add("*:S");//hide others
Process process = Runtime.getRuntime().exec(
commandLine.toArray(new String[0]));
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String line, log = "";
while ((line = bufferedReader.readLine()) != null) {
log += line + LINE_SEPARATOR;
}
From the docs for exec():
Executes the specified command and its arguments in a separate native process.
So it's running in a separate process. There's not really a good way to tell if it has finished before you start logging.
Instead of clearing the log, you could change the log TAG on each run. Just use the regular tag an append some number that identifies the run, even just a random one. Then when you collect your logs, you can filter by that, and only collect the ones you want.

Wrong output with logcat inside my application

I'm developing a multi-tab application. In one of the tab I want to show the logcat but I have a lot of problem running it correctly.
Right now I'm using the following command but I don't get anything in my TextView. :
Process process = Runtime.getRuntime().exec("/system/bin/logcat -s com.vittorio:I");
But when I run the same command into Terminal it works flawlessy.
I've also tryed this other command :
Process process = Runtime.getRuntime().exec("/system/bin/logcat *:I");
but for some reason it prints also Debug level messages ...
EDIT (1):
I've by-passed the problem by adding an high-level filter (java) to the whole log.. so I only print in my textview what I need. It's a very dirty solution but for now is the only one I managed to come with.
I would like to point out that I'me experiencing different behaviours on my phones :
Galaxy S Plus (rooted) : I can see the log.
Galaxy Y (rooted) : No log
Nexus One (not-rooted) : No log
EDIT (2) - SOLVED (NEED ROOTED PHONE):
After some struggling I managed to solve my problem. Actually navigating through the init.rc system file I saw that the permissions for /dev/log/main and /dev/log/system where setted to 620.. that's why I couldn't open the log on some of my phones. So I rooted also my Nexus One and added this commands into my activity before calling the logcat command :
Process process_su = Runtime.getRuntime().exec("su");
Process process_ch = Runtime.getRuntime().exec("chmod 777 /dev/log/main");
Done! :D
Hope this info will help anyone who will face my same issue.
You have to use this permission :
<uses-permission android:name="android.permission.READ_LOGS" />
and then you can use that snippet i found
try {
Process process = Runtime.getRuntime().exec("logcat -v");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
StringBuilder logString=new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
logString.append(line);
}
TextView tv = (TextView)findViewById(R.id.logTextView);
tv.setText(logString.toString());
} catch (IOException e) {
}
I didn't try it but it seems correct

Is it possible to call getevent from an Android service?

Is is possible to run getevent from an Android service and get output similar to what you see when running adb to call getevent from a command prompt on a development machine? When I try something like:
ProcessBuilder builder = new ProcessBuilder()
.command("getevent")
.redirectErrorStream(true)
.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(builder.getInputStream()));
...
the output I get for each device looks like:
could not open /dev/input/event[n], Permission denied
Is it just not possible to access low level information like this because of Android's security protections? Would it be possible on a "rooted" device?
Why I am trying to do this:
I would like to record a user's actions (touch and gesture events) on an Android device for the purpose of usability testing. An accessibility service seems to be the way to go, but the information is not detailed enough. For a swipe gesture, for example, I cannot get the screen coordinates of where the user swiped. I was thinking that getting the low-level input from the touch screen might let me get more detailed information. Maybe there is a better way to do this?
(I'm a newbie in the Android world. This kind of thing is easy on Windows.)
You can do like this.
th = new Thread(new Runnable(){
private Process exec;
#Override
public void run() {
try {
exec = Runtime.getRuntime().exec(new String[]{"su","-c","getevent -t " + device});
InputStreamReader is = new InputStreamReader(
exec.getInputStream());
String s;
BufferedReader br = new BufferedReader(is);
while(((s = br.readLine()) != null) && run){
...
}
is.close();
exec.destroy();
} catch (IOException e) {
e.printStackTrace();
}
}
You must use 'su' to get the root permission, but by this way you can't get the real time event, because there is a buffer size of 4k, you could get data only after contained 4k data.
Search for UIAutomator. This does what you want to do.
Your phone must be rooted to execute getevent/sendevent command.
One way is to install any terminal emulator from play store like Qute: Command Console & Terminal Emulator.
In terminal enter following:
1) su (it'll gain the root access required for getevent)
2) getevent (or getevent -c 8 to output only 8 lines else it would flood the terminal)

Categories

Resources