Read logcat from app not working correctly - android

I am trying to read from the logcat output in my app. I am able to read in correctly, but it goes on reading it in endless loop. Somehow there seems no way to detect the end of stream.
Not sure what I am doing wrong.
Here is my code:
String baseCommand = "logcat -v time MyTag:D *:S";
Process process = null;
try {
process = Runtime.getRuntime().exec(baseCommand);
InputStreamReader reader = new InputStreamReader(process.getInputStream());
BufferedReader bufferedReader = new BufferedReader(reader);
String line;
while ((line = bufferedReader.readLine()) != null) {
Log.d("SomeOtherTag", line); //This line executes endlessly
}
} catch (IOException e) {
Log.e(DEBUG_TAG, "error in logging");
e.printStackTrace();
}

Logcat doesn't exit so the buffer is blocked.
Use 'logcat -d' in order to dump the log and then exit.
Hope this still helps, Yaron

Not positive but I believe you need to pass the logcat call if it has args in a String[] so it would be something like
String[] baseCommand = {"logcat", "-v", "time", "MyTag:D", "*:S"};
then the rest of your code.
The single string call is just the program name, not the args.

Related

Android: Logcat string for Bluetooth ON

My application will switch on Bluetooth. I want to wait till bluetooth is switched on.
I will look for string
MESSAGE_BLUETOOTH_SERVICE_CONNECTED=1
in logcat and then proceed.
I want to know if this method is correct or i should be looking for some other string. What is the best way to know whether i am looking for right string in logcat. Is there any collection/document to learn what all info can be gathered using logcat
You have to be careful with below as logcat may prevent your app from responding. You should either run this piece of code or your own app in a seperate thread to keep it responsive. Below code asks logcat to send logs to your app and you can do investigate the logs as you see fit.
private static final String SEARCH_STRING = "MESSAGE_BLUETOOTH_SERVICE_CONNECTED=1";
try {
Process process = Runtime.getRuntime().exec("logcat");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
StringBuilder log=new StringBuilder();
String line = "";
boolean didFind = false;
while ((line = bufferedReader.readLine()) != null && !didFind) {
log.append(line);
didFind = line.toUpperCase().contains(SEARCH_STRING))
}
}
catch (IOException e) {}
I hope it helps.

How to collect LogCat messages in an Android application

I have an application and I'd like to collect the LogCat messages of a specified level and tag.
Can I somehow get the accumulated messages at some point? I don't want to collect the messages one by one, it should be the sum of them like when I use adb to read the actual log. Is this possible?
Try this: Note that in Android 4 you will only see the log messages that were written by your own app unless you have root access.
public static String getLog(Context c) {
try {
Process process = Runtime.getRuntime().exec("logcat -d");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder log = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
log.append(line);
log.append("\n");
}
return log.toString();
} catch (IOException e) {
return null;
}
}
Why not just write them to a file instead? LogCat is really for real-time logs. There are lots of good quality logging packages that can log to a file if that's what you want to do.
Just as an example:
How to write logs in text file when using java.util.logging.Logger

how to send a command at runtime using "su" and get all lines back from DataInputStream

I am working on a program that needs to be able to determine what is on the android device at Xlocation. I am using "su ls Xlocation"
I want to get back and array list of files but only manage to get back the first Item. Am I missing a command that gets the next line? Or is there something else I need to do.
Below is my command I am sending
String[] commands = new String[]{"ls /system/app/"};
return doCommand(commands);
Below is my current method for doCommand
private boolean doCommand(String[] commands)
{
ArrayList<String> output = new ArrayList<String>();
boolean ran = false;
try
{
Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
DataInputStream ins = new DataInputStream(process.getInputStream());
// This part works I sends the command right!
for (String single : commands)
{
os.writeBytes(single + "\n");
os.flush();
os.writeBytes("exit\n");
os.flush();
process.waitFor();
ran = true;
}
int av = -1;
while (av != 0)
{
//////////////////////////// WORKING ON THIS TO GET ALL INFO /////////////////
av = ins.available();
if (av != 0)
{
byte[] b = new byte[av];
ins.read(b);
output.add(new String(b));
System.out.println(new String(b) + "Recieved form modem");
}
}
}
catch(Exception ex){}
return ran;
}
As seen currently it only returns true or false. However run in debug I only get the first item in output. (output = "[first.apk")
Edited Newer Version;
public ArrayList<String> doCommand(String[] commands)
{
ArrayList<String> output = new ArrayList<String>();
try
{
Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
DataInputStream ins = new DataInputStream(process.getInputStream());
for (String single : commands)
{
os.writeBytes(single + "\n");
//os.flush();
output.add("true");
}
os.writeBytes("exit\n");
byte[] bc = new byte[10000];
String st = "";
while(ins.read(bc) != -1)
{
st += new String(bc);
os.flush();
}
output.add(st);
os.flush();
os.close();
ins.close();
process.waitFor();
}
catch(Exception ex)
{}
return output;
}
Now getting a decent amount of output but still not all where the directory has large items inside size limit of byte[10000] I have checked.
If anyone wants to improve on this and get an exact answer that works do so I still check this post.
Thanks
You can try adapting this method from my open source User Management (GitHub) app to do what you want. This will read each and every line of the output following a terminal command:
public static String[] getUserList()
{
Process p;
try {
p = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
BufferedReader bf = new BufferedReader(new InputStreamReader(p.getInputStream()));
os.writeBytes("pm list-users"+"\n");
os.writeBytes("exit\n");
ArrayList<String> users = new ArrayList<String>();
String test;
bf.readLine();
while((test = bf.readLine()) != null)
{
users.add(test);
}
String[] userList = (String[]) users.toArray(new String[users.size()]);
os.flush();
return userList;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
I'm a bit new to Java but I believe the issue is just a minor oversight.. ne in which I've run into a few times with Python ;)
Because you've added the below into your while loop:
os.writeBytes("exit\n");
os.flush();
After each iteration you are attempting to exit the terminal session. After the first iteration the terminal session would already be closed so this would explain why only the first result would be returned.
I would suggest adding the exit code after the while loop completes to ensure you are not sending the rest of the commands to a dead session. Alternatively you could recreate os during each iteration as well but that seems a bit redundant. ;)
Edit #1
I'm not familiar with the usage of bytes, but I have been able to parse the output of my commands with a similar while loop. I Also added stderr to the input to ensure the buffer is emptied when needed. Upon first glance at your new code, it appears you are defining a new String during each iteration of the while loop, instead of appending the line to a variable. This would cause your variable to be overwritten during each iteration. ;)
Below is some code I've used in the past to accomplish similar tasks. I quickly modified from my source but I am currently unable to give it a test run. Keep in mind that your os
is my stdout, and your ins is my stdin.
Runtime terminal = (Runtime) Runtime.getRuntime();
Process process = terminal.exec("su");
DataOutputStream stdout = new DataOutputStream(process.getOutputStream());
InputStream stderr = process.getErrorStream();
BufferedReader stdin = new BufferedReader(new InputStreamReader(stderr));
String line = "";
String output = "";
// Execute command and flush
stdout.writeBytes("your command here\n");
stdout.flush();
// Append stdin.readLine() to output variable until line is null
while ((line = stdin.readLine()) != null)
output += line;
// I've had mixed luck getting waitFor() to work, but technically it should force
// the shell to wait until the command completes. Uncomment it to try it out.
//process.waitFor();
stdout.writeBytes("exit\n");
stdout.flush();
// Print output to logcat
System.out.println(output);

why process give null inputstream in test runner class?

In my android test project, I simply read the logcat using adb command
like,
public StringBuilder log=new StringBuilder();
public String line="";
public String temp="";
public void testSolo() throws Exception {
String baseCommand = "logcat -v time";
baseCommand += " ActivityManager:I "; // Info for my app
baseCommand += " *:S "; // Silence others
try {
Process logReaderProcess = Runtime.getRuntime().exec(baseCommand);
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(logReaderProcess.getInputStream()));
while ((line =bufferedReader.readLine()) != null) {
log.append(line); // here readLine() returns null
}
}
catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
but, here in string line I always get null value,
while the same thing always run in the android activity's onCreate() .
I don't understand why this happen?
Same thing runs in activity class and not in the android test project.
I also add use -permission for READ_LOGS and WRITE_EXTERNAL_STORAGE in test project's
manifest.xml file.
Is there anybody knows how it works or what happens?
Thanks in advance.
Try to add
<uses-permission android:name="android.permission.READ_LOGS" />
to your manifest.
String []baseCommand = new String[]{"logcat", "-v","time"};
Process logReaderProcess = Runtime.getRuntime().exec(baseCommand);
try this out

Reading Logcat within the app returns null

I read the other posts and can't figure out the "trick".
I looked at Log Collector but can't use a separate APK. I'm basically using the same approach and I consistently get nothing back on the processes inputstream.
I have READ_LOGS in the manifest.
From within my default activity, I'm able to get the log, but if I move the logic to another activity or utilize an asynctask, no output is returned.
this code is from my default activity... inline, i dump it to the log
try {
Process process = Runtime.getRuntime().exec("logcat -d");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
StringBuilder log=new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
log.append(line);
}
Log.d(LOGTAG, "Logcat: " +log.toString());
} catch (IOException e) {}
if i wrap it in an asynctask or just inline it in another activity, it returns nothing
ArrayList<String> commandLine = new ArrayList<String>();
//terminate on completion and suppress everything except the filter
commandLine.add("logcat -d -s");
...
//replace asynctask with inline (could not get log in asynctask)
showProgressDialog(getString(R.string.acquiring_log_progress_dialog_message));
final StringBuilder log = new StringBuilder();
BufferedReader bufferedReader = null;
try{
Process process = Runtime.getRuntime().exec(commandLine.toArray(new String[0]));
bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null){
log.append(line);
log.append(MangoApp.LINE_SEPARATOR);
}
sendIntent.putExtra(Intent.EXTRA_TEXT, log.toString());
startActivity(Intent.createChooser(sendIntent, getString(R.string.chooser_title)));
dismissProgressDialog();
dismissMainDialog();
finish();
}
catch (IOException e){
dismissProgressDialog();
showErrorDialog(getString(R.string.failed_to_get_log_message));
Log.e(LOGTAG, "Log collection failed: ", e);//$NON-NLS-1$
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ignore) {}
}
}
Can anyone spot the diff or explain the magic? I'm pretty sure the commandline is right in the second version so scratching my head. I'm using 2.1 SDK 7 on the emulator.
Thanks
Hope this will be helpful, you don't have to create file by your self just execute the below command, to get the error info.
Runtime.getRuntime().exec("logcat -v time -r 100 -f /sdcard/log.txt *:E");
Logcat parameters options:
-r <size in kilobytes> -> for specifying the size of file
-f <filename> -> file to which you want to write the logs.
Can you try it without the ArrayList. Just pass the command String
I have implemented it in the following way (without the ArrayList). It works for me.
String baseCommand = "logcat -v time";
baseCommand += " MyApp:I "; // Info for my app
baseCommand += " *:S "; // Silence others
ServicesController.logReaderProcess = Runtime.getRuntime().exec(baseCommand);

Categories

Resources