Does anyone know how to get the android device system log programatically using Java? This would be something similar to what is available on lower panel on the Dalvik Debug Monitor.
Thanks in advance.
Untested with 'adb shell logcat', but I've used this to get other things from via adb:
public static String[] getAdbLogCat() {
try {
Process p = Runtime.getRuntime().exec("/path/to/adb shell logcat");
InputStream is = p.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
final StringBuffer output = new StringBuffer();
String line;
ArrayList<String> arrList = new ArrayList<String>();
while ((line = br.readLine()) != null) {
System.out.println(line);
}
return (String[])arrList.toArray(new String[0]);
} catch (IOException e) {
System.err.println(e);
e.printStackTrace();
return new String[]{};
}
}
I started with Mathias Conradt's answer above. It didn't work for me, but after working with it for a long time, I found out what tweaks it needed to get it working right. This will work. It doesn't require root access, special permissions, or anything.
private static String getAdbLogCat()
{
String log = "";
String str;
try
{
String myStringArray[]= {"logcat", "-d"};
Process process = Runtime.getRuntime().exec(myStringArray);
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
str = br.readLine();
while (str != null)
{
log += str;
str = br.readLine();
}
}
catch (IOException e)
{
}
return log;
}
Related
I'm trying to grep log from android device on runtime to perform assertion, is there a way I can achieve the same, while passing below code seems working but its keep running, how can I end this after certain time
String log = "";
String str;
try {
String myStringArray[]= {"logcat", "| grep XYZ "};
Process process = Runtime.getRuntime().exec(myStringArray);
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
str = br.readLine();
while (str != null) {
log += str;
str = br.readLine();
}
} catch (IOException e) {
System.out.println("Getting IOException .......");
}
return log;
} ```
I believe I'm missing something here
I want to read the stdout of a process right as it is generated.
The process will send information for a progress indicator, so it doesn't make sense that I get the information all at once, which I do and which is the problem. I tried to use Scanner class as suggested in a post, but I still get the output only after the process has finished.
I realize this question has been asked before, but it hasn't been answered.
You will probably want to look at class StreamGobblerOutput first.
public List<String> executeCall(String fileName)
{
StringBuilder sbOutput = new StringBuilder();
StringBuilder sbError = new StringBuilder();
File file = new File(fileName);
try ( BufferedReader br = new BufferedReader(new FileReader(file)) ) {
String line;
while ((line = br.readLine()) != null) {
String [] parts = line.split("\\s");
if(parts.length<2) {
sbError.append("Command too short for call: " + parts[0]);
continue;
}
List<String> args = new ArrayList<String>();
args.add ("sfb.exe");
for(int i = 1; i <parts.length; ++i) {
args.add (parts[i]);
}
args.add (sfbPassword);
ProcessBuilder pb = new ProcessBuilder (args);
pb.directory(new File(Support.getJustThePathFromFile(file)));
Map<String, String> envs = pb.environment();
String path = envs.get("Path");
envs.put("Path", Paths.get(".").toAbsolutePath().normalize().toString() + ";" +path);
//pb.redirectOutput(new Redirect() {});
Process p = pb.start();
String outputPathPrefix = pb.directory().getCanonicalPath();
// any output?
StreamGobblerOutput outputGobbler = new StreamGobblerOutput(p.getInputStream(), outputPathPrefix);
outputGobbler.start();
// any errors?
StreamGobblerError errorGobbler = new StreamGobblerError(p.getErrorStream());
errorGobbler.start();
try
{
p.waitFor();
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
sbOutput = outputGobbler.getOutput();
sbError = errorGobbler.getErrors();
String rootPath= Support.getJustThePathFromFile(new File(fileName));
File rootFile = new File(rootPath + "/..");
String rootFolder = rootFile.getCanonicalFile().getName();
System.err.println("rootFolder: " + rootFolder);
mainApp.addModifiedFiles(outputGobbler.getModifiedFileNames(), rootFolder);
}
} catch ( IOException ex) {
sbError.append(ex.getMessage());
}
mainApp.addOutput(sbOutput.toString());
mainApp.addError(sbError.toString());
return;
}
private class StreamGobblerOutput extends Thread {
private InputStream is;
private String outputPathPrefix;
private StringBuilder sbOutput;
private List<String> modifiedFileNames;
private Scanner scanner;
private StreamGobblerOutput(InputStream is, String outputPathPrefix) {
this.is = is;
this.outputPathPrefix = outputPathPrefix;
sbOutput = new StringBuilder();
modifiedFileNames = new ArrayList<String>();
scanner = new Scanner(is);
}
public StringBuilder getOutput() {
return sbOutput;
}
public List<String> getModifiedFileNames() {
return modifiedFileNames;
}
#Override
public void run() {
//create pattern
Pattern patternProgress = Pattern.compile("\\((\\d+)%\\)");
//InputStreamReader isr = new InputStreamReader(is);
//BufferedReader br = new BufferedReader(isr);
String ligne = null;
while (scanner.hasNextLine()) {
ligne = scanner.nextLine();
sbOutput.append(ligne);
sbOutput.append("\r\n");
//bw.write("\r\n");
Matcher mProgress = patternProgress.matcher(ligne);
if (mProgress.find()) {
int percentage = Integer.parseInt(mProgress.group(1));
System.err.println("percentage=" + percentage);
mainApp.mainWindowController.setProgressExecute(percentage/100.0);
}
}
mainApp.mainWindowController.setProgressExecute(1.0);
if (scanner != null) {
scanner.close();
}
}
}
private class StreamGobblerError extends Thread {
private InputStream is;
private StringBuilder sbError;
private Scanner scanner;
private StreamGobblerError(InputStream is) {
this.is = is;
sbError = new StringBuilder();
scanner = new Scanner(is);
}
public StringBuilder getErrors() {
return sbError;
}
#Override
public void run() {
//InputStreamReader isr = new InputStreamReader(is);
//BufferedReader br = new BufferedReader(isr);
String ligne = null;
while (scanner.hasNextLine()) {
ligne = scanner.nextLine();
sbError.append(ligne);
sbError.append("\r\n");
}
if (scanner != null) {
scanner.close();
}
}
}
Update: I tried redirecting the output to a file and reading from it, but it appears this runs into the same buffering problem as the previous implementation: I get only two data points.
As a workaround, I will have to ask the creator of the .exe to include 4100 extra characters in each line showing the progress.
If your external process is C/C++ (stdio) based, than this is most likely a block buffering issue:
stdio-based programs as a rule are line buffered if they are running interactively in a terminal and block buffered when their stdout is redirected to a pipe. In the latter case, you won't see new lines until the buffer overflows or flushed.
see this answer for more details, and some possible workarounds.
Please also note that according to this, line buffering is not an option on Win32:
_IOLBF
For some systems, this provides line buffering. However, for Win32, the behavior is the same as _IOFBF - Full Buffering.
so if you choose to modify the "exe" program to set a proper output mode with setvbuf, you would have to use:
_IONBF No buffer
instead.
From the Javadocs
Optionally, a PrintStream can be created so as to flush automatically;
this means that the flush method is automatically invoked after a byte
array is written, one of the println methods is invoked, or a newline
character or byte ('\n') is written.
Reference: http://docs.oracle.com/javase/8/docs/api/java/io/PrintStream.html
One way to do this is to have output stream flush() after every write.
System.out.flush()
You could also define your own flushable PrintStream and use that.
I'm performing the following code to execute linux commands in my android application that I'm creating:
public void RunAsRoot(String[] cmds){
Process p = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
for (String tmpCmd : cmds) {
os.writeBytes(tmpCmd+"\n");
}
os.writeBytes("exit\n");
os.flush();
}
I want to know if there is a way to know what the command is returning after it is executing. for example, if I do "ls" I would like to see what the command wold normally output.
try this code :
try {
Process process = Runtime.getRuntime().exec("ls");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
StringBuilder result=new StringBuilder();
String line = "";
while ((line = bufferedReader.readLine()) != null) {
result.append(line);
}
TextView tv = (TextView)findViewById(R.id.textView1);
tv.setText(result.toString());
}
catch (IOException e) {}
Let's go by a "String function" example
String shell_exec(String s)
{
String line="",output="";
try
{
Process p=Runtime.getRuntime().exec(new String[]{"sh","-c",s});
BufferedReader b=new BufferedReader(new InputStreamReader(p.getInputStream()));
while((line=b.readLine())!=null){output+=line+"\r\n";}
}catch(Exception e){return "error";}
return output;
}
Now just use it:
String s=shell_exec("ls /data/data/com.mycompany.myapp");
everyone, I have a process that needs to get standard output and log/error/exception output from the subprocess. The standard output is fine, but I can't get ErrorStream, therefore the program is stuck there because of that. Here is my simple code. There is nothing magic, but why can't I get the error stream here? Thanks for looking at it.
BufferedReader standard =
new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader error =
new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line = null;
while ((line = standard.readLine()) != null) {
System.out.println(line);
}
while ((line = error.readLine()) != null) {
System.out.println(line);
}
Now, as suggested, i used two threads to process the output and error streams, but still had the same problem, as follows. Can anybody give me some insights? Thanks.
ProcessBuilder pb = new ProcessBuilder(listArgs);
pb.redirectErrorStream();
Process process = pb.start();
StreamThread output = new StreamThread(process.getInputStream());
StreamThread error = new StreamThread(process.getErrorStream());
output.start();
error.start();
while (true) {
try {
output.join();
break;
}
catch (InterruptedException ie) {
ie.printStackTrace();
}
}
The definition of the StreamThread:
public static class StreamThread extends Thread{
private InputStream input = null;
public StreamThread(InputStream in){
input = in;
}
String line = null;
public void start(){
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
try{
while( (line=reader.readLine()) != null ){
System.out.println(line);
}
reader.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
Look at your loops:
while ((line = standard.readLine()) != null) {
System.out.println(line);
}
while ((line = error.readLine()) != null) {
System.out.println(line);
}
You're going to keep reading from the output stream until it's finished - which is likely to be when the process terminates. Only then do you start reading the error stream.
You should probably put at least one of these into a different thread, so you can read from both streams at the same time.
This piece of code is creating memory leak issues cause of BufferedReader and InputStreamReader which I think might be happening cause of some exceptions. How should I change it?
try{
URL url = new URL(sMyUrl);
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
while ((str = in.readLine()) != null) {
jsonString += str;
}
in.close();
}catch(Exception e){
}
It would be safer to close your stream using a try..finally block. You might also use a StringBuilder as it is designed for concatenating strings. You should also avoid catching Exception and doing nothing with it. Also, your code is concatenating lines without any line-breaks. This may well not be what you want, in which case append("\n") when you read each line in.
Here's a version with those modifications:
StringBuilder json = new StringBuilder();
try {
URL url = new URL(sMyUrl);
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
try {
String str;
while ((str = in.readLine()) != null) {
json.append(str).append("\n");
}
} finally {
in.close();
}
} catch (Exception e) {
throw new RuntimeException("Failed to read JSON from stream", e);
}
The code isn't pretty but won't be creating a memory leak. I suggest you use a memory profiler to determine where your memory is being used. Otherwise you are just guessing even if you have ten + years experience performance tuning in Java ;)
A better alternative is to use Java 7
URL url = new URL(sMyUrl);
try(BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()))) {
while ((str = in.readLine()) != null) {
jsonString.append(str).append("\n");
}
}
If you have Java 6 or older you can use.
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()))) {
try {
while ((str = in.readLine()) != null) {
jsonString.append(str).append("\n");
}
} finally {
in.close();
}