I want to write logcat results to a file in the background via a service. I have created a service and used the following code for having the logcat results.
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);
}
Now with the above code, I am able to just write some of the logs only and if I remove the "-d" option then the service crashed.
You have to have the phone rooted with priveleges R/W to that now.
Grant permissions to READ_LOGS on Manifest.xml.
Then write this code in OnCreate() of the Activity
String pname = getPackageName();
String[] CMDLINE_GRANTPERMS = { "su", "-c", null };
if (getPackageManager().checkPermission(android.Manifest.permission.READ_LOGS, pname) != 0) {
Log.d(TAG, "we do not have the READ_LOGS permission!");
if (android.os.Build.VERSION.SDK_INT >= 16) {
Log.d(TAG, "Working around JellyBeans 'feature'...");
try {
// format the commandline parameter
CMDLINE_GRANTPERMS[2] = String.format("pm grant %s android.permission.READ_LOGS", pname);
java.lang.Process p = Runtime.getRuntime().exec(CMDLINE_GRANTPERMS);
int res = p.waitFor();
Log.d(TAG, "exec returned: " + res);
if (res != 0)
throw new Exception("failed to become root");
} catch (Exception e) {
Log.d(TAG, "exec(): " + e);
Toast.makeText(getApplicationContext(), "Failed to obtain READ_LOGS permission", Toast.LENGTH_LONG).show();
}
}
} else
Log.d(TAG, "we have the READ_LOGS permission already!");
and then your code should work, run this instead if not
Process process = Runtime.getRuntime().exec("su -c logcat D");
Related
I need to read and filter logcat logs within my application, of others applications. I found other questions and the most useful if Read logcat programmatically within application.
So I tried to write my code, but the result is always the same, that is it returns the logcat logs that made until the application was started.
public void getLog() {
edLog.setText("");
Log.e("imgspa", "ciao");
try {
//Process logcat = Runtime.getRuntime().exec(new String[]{"logcat", "-d", "*:I"});
//Process logcat = Runtime.getRuntime().exec(new String[]{"logcat", "-d", "B4A:I"});
//Process logcat = Runtime.getRuntime().exec(new String[]{"logcat", "-d", "-v", "time", "-e", "*VFY*"});
//Process logcat = Runtime.getRuntime().exec(new String[]{"logcat", "-d", "-v", "time", "*:I"});
//Process logcat = Runtime.getRuntime().exec(new String[]{"logcat", "-d"});
Process logcat = Runtime.getRuntime().exec(new String[]{"logcat", "-d", "-v", "threadtime", "*:*"});
BufferedReader br = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
String line;
final StringBuilder sb = new StringBuilder();
String separator = System.getProperty("line.separator");
sb.append("inizio");
sb.append(separator);
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append(separator);
}
sb.append("fine");
edLog.setText(sb.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
As you can see I tried different solutions but no one can help me.
I need to get the logcat, where the application name is "B4A".
Let me point out that:
- I have a rooted device
- I already added the READ_LOGS permissions
As of JellyBean, you cannot access the log in logcat that was not add there by your application.
link
Since Android 4.1 it's no possible to read logs of other applications.
See an explanation
For rooted device you need to obtain the READ_LOGS permission manually
String pname = getPackageName();
String[] CMDLINE = { "su", "-c", null };
if(getPackageManager().checkPermission(android.Manifest.permission.READ_LOGS, pname) != 0) {
try {
CMDLINE[2] = String.format("pm grant %s android.permission.READ_LOGS", pname);
java.lang.Process p = Runtime.getRuntime().exec(CMDLINE);
int res = p.waitFor();
Log.d(TAG, "exec returned: " + res);
if (res != 0)
throw new Exception("failed to become root");
} catch (Exception e) {
Log.d(TAG, "exec(): " + e);
}
}
Or just try it with .exec("su -c logcat -d")
The change is that third party applications can no longer get the read logs permission, however every app can read the logs containing only the lines they have written, without needing any permission.
Unless you rooted you cannot do this since Jelly Bean. See this Android bug report and this related discussion. Quote:
img.simone For more query you have to read this
Hope it will help you!!
I have an Activity which every second write a counter to the logcat:
Runnable rLog = new Runnable() {
#Override
public void run() {
i++;
Log.d("bbb", "i= " + i);
handler.postDelayed(this, 1000);
}
};
In addition - I have a service which read from "logcat -s bbb" and log it:
Runnable rGetLog = new Runnable() {
#Override
public void run() {
Runtime rt = Runtime.getRuntime();
Process process = null;
try {
process = rt.exec("logcat -s bbb");
} catch (IOException e1) {
e1.printStackTrace();
}
BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
try {
while ((line = bufferedReader.readLine()) != null)
{
Log.d("aaa", "get line = " + line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
This code works well. The problem starts when I change the tag "bbb" to a real tag such as "AndroidRuntime" or another tag... I got an empty response from logcat
(if I run at the same time "logcat -s AndroidRuntime" from adb I got lots of lines...)
Who knows what the problem is? what can be different?
Thanks!
From Android Jelly Bean, applications cannot read log entries from other applications, unless your device is rooted and you read the logs as superuser.
try using sudo to get permissions:
process = rt.exec("su && logcat -s YOUR_TAG");
TL:DR; version ;)
my app should run without user interaction (autostart etc works)
it should update itself (via apk) without any user interaction
rooted devices are possible
.
problem:
querying a newer apk from a server works
when starting the apk with a (view?) intent, the "install app" prompt pops and needs a user confirmation
How do I solve this without any user interaction?
http://code.google.com/p/auto-update-apk-client/
This seems to be a solution, but there must be better approach.
I already found this: Install Application programmatically on Android
but that doesn't solve my problem.
Solved it! :D
It just works in rooted devices but works perfectly.
Using the unix cmd "pm" (packageManager) allows you to install apks from sdcard, when executing it as root.
Hope this could help some people in the future.
public static void installNewApk()
{
try
{
Runtime.getRuntime().exec(new String[] {"su", "-c", "pm install -r /mnt/internal/Download/fp.apk"});
}
catch (IOException e)
{
System.out.println(e.toString());
System.out.println("no root");
}
}
Required permissions:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
My suggestion is to use plugin mechanism instad of updating the app. You can dynamically load classes from the Web and run them inside your app without any user interaction. There is a lot of resources spread across the Internet:
How to load a Java class dynamically on android/dalvik?
http://android-developers.blogspot.com/2011/07/custom-class-loading-in-dalvik.html
If su -c doesn't work, try su 0 (only rooted devices can do su!)
The full answer looks like this:
private void installNewApk()
{
String path = mContext.getFilesDir().getAbsolutePath() + "/" + LOCAL_FILENAME;
mQuickLog.logD("Install at: " + path);
ProcessUtils.runProcessNoException(mQuickLog, "su", "0", "pm", "install", "-r", path);
}
With this class defined:
public class ProcessUtils {
Process process;
int errCode;
public ProcessUtils(String ...command) throws IOException, InterruptedException{
ProcessBuilder pb = new ProcessBuilder(command);
this.process = pb.start();
this.errCode = this.process.waitFor();
}
public int getErrCode() {
return errCode;
}
public String getOutput() throws IOException {
InputStream inputStream = process.getInputStream();
InputStream errStream = process.getErrorStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
String line;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line + System.getProperty("line.separator"));
}
br = new BufferedReader(new InputStreamReader(errStream));
while ((line = br.readLine()) != null) {
sb.append(line + System.getProperty("line.separator"));
}
return sb.toString();
}
public static String runProcess(String ...command) throws IOException, InterruptedException {
ProcessUtils p = new ProcessUtils(command);
if (p.getErrCode() != 0) {
// err
}
return p.getOutput();
}
public static void runProcessNoException(String ...command) {
try {
runProcess(command);
} catch (InterruptedException | IOException e) {
// err
}
}
}
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);
Please Tell me it is possible to run a shell script file from My Android application.
and read the data from script file.
If it is possible than how to proceed , Please give me some guideline.
You can use this code snippet (from Aaron C)
void execCommandLine(String command)
{
Runtime runtime = Runtime.getRuntime();
Process proc = null;
OutputStreamWriter osw = null;
try
{
proc = runtime.exec("su");
osw = new OutputStreamWriter(proc.getOutputStream());
osw.write(command);
osw.flush();
osw.close();
}
catch (IOException ex)
{
Log.e("execCommandLine()", "Command resulted in an IO Exception: " + command);
return;
}
finally
{
if (osw != null)
{
try
{
osw.close();
}
catch (IOException e){}
}
}
try
{
proc.waitFor();
}
catch (InterruptedException e){}
if (proc.exitValue() != 0)
{
Log.e("execCommandLine()", "Command returned error: " + command + "\n Exit code: " + proc.exitValue());
}
}
But this requires root access I think.
You could also try to use GScript
I've been using this to run shell scripts in my android app. Only thing I've yet to figure out how to do is direct the output to where I want it. You don't need root for this, which is why I'm posting.
Process process = Runtime.getRuntime().exec("top -n 1");
//Get the output of top so that it can be read
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));