How do I access production Android logs? [duplicate] - android

I'm working on an app that uses Android's MediaMuxer for recording the screen. Using Crashlytics, a significant number of users have the "Failed to stop the muxer" crash, but I can't reproduce it locally on any of my devices. According to another question, the MPEG4Writer logs generated while MediaMuxer is running should indicate what the source of the problem is, but since I'm unable to reproduce it locally, I need to collect those logs remotely and pass them over to Crashlytics.
So here's my problem: MediaMuxer and MPEG4Writer are system classes, so obviously I can't edit them to add Crashlytics.log() lines. I've thought of having the app read the Logcat output and storing all entries containing MPEG4Writer, which are then sent to Crashlytics if the muxer crashes, using this implementation as a base. Here's my code:
public class LogRetriever extends Thread {
private static final String TAG = LogRetriever.class.getCanonicalName();
public static ArrayList<String> logStorage = new ArrayList<>();
private AtomicBoolean mLoggingActive = new AtomicBoolean(true);
#Override
public void run() {
try {
String[] command = new String[] { "logcat" };
Process process = Runtime.getRuntime().exec(command);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while (mLoggingActive.get() && ((line = bufferedReader.readLine()) != null)){
if(line.contains("MPEG4Writer")) {
logStorage.add(line);
}
}
}
catch (IOException ex) {
Log.e(TAG, "start failed", ex);
}
}
public void stopLogging() {
mLoggingActive.set(false);
}
}
Using the above method, I only seem to get the first four log lines generated by MPEG4Writer. The rest are visible through Android Studio's logcat, but aren't collected by my code. I've also tried this library which seems to do the same thing, but again, same problem, only the first 4 lines are collected. I suspect that MediaMuxer is creating its own process after those 4 lines, at which point I can no longer read its logcat output because my LogRetriever class is now in a different process. So how am I supposed to collect those logs? Am I taking the wrong approach here?

So how am I supposed to collect those logs?
Generally, unless you are working for a device manufacturer, you don't collect those logs.
First, accessing LogCat at runtime has never been officially supported; hence, the clunky "fork logcat" approach that you have to take.
Beyond that, you need the READ_LOGS permission to get more than what you are. That permission has signature|privileged|development for the protectionLevel, meaning that ordinary apps cannot hold that permission.
This is for privacy reasons. READ_LOGS gives you access to all of LogCat, and lots of apps (and some system processes) log information that may be sensitive.

Related

Viewing logcat in tablet

Is there a way to view the log on a tablet running 4.4? I've downloaded several apps like aLogCat and none of them show what my app writes out with S.o.p or Log.d. I have an intermittent bug that gives the Unfortunately appname has stopped message.Is there any way to view the log after this event without having to connect to a PC and use the adb program?
What other ways are there to get debug output? Would trapping the System.out and System.err classes get the stack trace?
Thanks,
Norm
You're focussing on tring to read out logcat, but there are better solutions for reading crash logs. My personal preference is Crashlytics, which automatically logs fatal exceptions and provides mechanisms for logging other messages.
The way all these crash reporters work, is by defining a UncaughtExceptionHandler:
Thread.setDefaultUncaughtExceptionHandler(
new MyUncaughtExceptionHandler(this));
If you prefer to use your own solution, you may want to look into using this. See this related question for more details.
Is there a way to view the log on a tablet running 4.4?
No, sorry. An app can only see its own log messages, not those from other apps. Hence, a third-party log viewer cannot see your app's messages.
Is there any way to view the log after this event without having to connect to a PC and use the adb program?
Use any standard crash management library, like ACRA, or services like Crashlytics, BugSense, etc.
The AIDE Application (Android Integrated Development Environment) allows one to develop android Apps directly on android device.
One particular feature is to read the logcat.
You can get it here https://play.google.com/store/apps/details?id=com.aide.ui
Here's the code I've put in the program. It seems to work:
// Define inner class to handle exceptions
class MyExceptionHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e){
java.util.Date dt = new java.util.Date();
String fn = LogFilePathPfx + "exception_" + sdf.format(dt) + ".txt";
try{
PrintStream ps = new PrintStream( fn );
e.printStackTrace(ps);
ps.close();
System.out.println("wrote trace to " + fn);
e.printStackTrace(); // capture here also???
SaveStdOutput.stop(); // close here vs calling flush() in class
}catch(Exception x){
x.printStackTrace();
}
lastUEH.uncaughtException(t, e); // call last one Gives: "Unfortunately ... stopped" message
return; //???? what to do here
}
}
lastUEH = Thread.getDefaultUncaughtExceptionHandler(); // save previous one
Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler());

How to Replicate Java console behaviour in Android App

I have a Java SE Application that use
input = new Scanner(System.in);
to get Input parameters
and use System.out.println("..");
to print results
Since all Java APIs used in the original Java Project are also available in Android, I have tried to import all classes without any error, but now I don't know how replicate the behaviour of the classic Java console in Android.
I have seen that there are developers that have achieved this in some IDE-like apps, but I don't know how.
Could you help me?
Example:
assume that you want to port this dummy Java SE Application in Android mantaining the console-like approach of the original code
public static void main(String[] args) {
System.out.println("Please enter your choice");
System.out.println("A, B");
Scanner myScanner = new Scanner(System.in);
String choice = myScanner .nextLine();
if (choice.charAt(0) == 'A') {
...do something
}
else{
...do something
}
}
You can execute system commands with exec(). Here is how to do it:
Runtime r = Runtime.getRuntime();
Process p = r.exec("uname -a"); // here goes your input
p.waitFor();
BufferedReader b = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = b.readLine()) != null) {
System.out.println(line);
}
Update:
Ok, from what I understand, you would like to compile and run code written by user. I can see 3 options:
Most difficult I think. Get the source code of some Java compiler and include it in your project. So, user inputs a text. You compile it, run and give the output.
Using already built compiler. This requires root. Install javac on your device. Then, in your application you can call it with the above exec() code.
Easiest one. Using internet and for example, Ideone.com. In your app you send code to compile on Ideone. You get back the output and present it to the user.

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.

Android StrictMode and heap dumps

When Android's StrictMode detects a leaked object (e.g. activity) violation, it would be helpful if I could capture a heap dump at that moment in time. There's no obvious way, however, to configure it to do this. Does anyone know of some trick that can be used to achieve it, e.g. a way to convince the system to run a particular piece of code just prior to the death penalty being invoked? I don't think StrictMode throws an exception, so I can't use the trick described here: Is there a way to have an Android process produce a heap dump on an OutOfMemoryError?
No exception, but StrictMode does print a message to System.err just before it terminates. So, this is a hack, but it works, and as it's only going to be enabled on debug builds I figure it's fine... :)
in onCreate():
//monitor System.err for messages that indicate the process is about to be killed by
//StrictMode and cause a heap dump when one is caught
System.setErr (new HProfDumpingStderrPrintStream (System.err));
and the class referred to:
private static class HProfDumpingStderrPrintStream extends PrintStream
{
public HProfDumpingStderrPrintStream (OutputStream destination)
{
super (destination);
}
#Override
public synchronized void println (String str)
{
super.println (str);
if (str.equals ("StrictMode VmPolicy violation with POLICY_DEATH; shutting down."))
{
// StrictMode is about to terminate us... don't let it!
super.println ("Trapped StrictMode shutdown notice: logging heap data");
try {
android.os.Debug.dumpHprofData(app.getDir ("hprof", MODE_WORLD_READABLE) + "/strictmode-death-penalty.hprof");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
(where app is a static field in the outer class containing a reference to the application context, for ease of reference)
The string it matches has survived unchanged from gingerbread release all the way up to jelly bean, but it could theoretically change in future versions, so it's worth checking new releases to ensure they still use the same message.

TransactionTooLargeEception when trying to get a list of applications installed

As part of my app I get a list of apps installed on the device by using ApplicationPackageManager.getInstalledApplications but for some users I get crash reports saying that
TransactionTooLargeException at android.osBinderProxy.tranasact(Native Method)
Can anyone think why I'd get this?
I've found that this was solved on Android 5.1 (proof here, search for "Fix package manager TransactionTooLargeExceptions") as it was reported on multiple places:
https://code.google.com/p/android/issues/detail?id=95749
https://code.google.com/p/android/issues/detail?id=93717
https://code.google.com/p/android/issues/detail?id=69276
However, I wanted to solve this for pre-5.1, so I've come up with a solution (and suggested Google to put it on the support library, here) . Here's a short code version of what I've suggested:
public static List<PackageInfo> getInstalledPackages(Context context,int flags)
{
final PackageManager pm=context.getPackageManager();
try
{
return pm.getInstalledPackages(flags);
}
catch(Exception ignored)
{
//we don't care why it didn't succeed. We'll do it using an alternative way instead
}
// use fallback:
Process process;
List<PackageInfo> result=new ArrayList<>();
BufferedReader bufferedReader=null;
try
{
process=Runtime.getRuntime().exec("pm list packages");
bufferedReader=new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while((line=bufferedReader.readLine())!=null)
{
final String packageName=line.substring(line.indexOf(':')+1);
final PackageInfo packageInfo=pm.getPackageInfo(packageName,flags);
result.add(packageInfo);
}
process.waitFor();
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
if(bufferedReader!=null)
try
{
bufferedReader.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
return result;
}
What it does it to try using the official way first, and then, if failed, it fetches the package names using ADB command, and get the information of each of the apps, one after another.
It is much slower than the official one, but it didn't crash for me. I've tested it on Android emulators (2.3.x till 5.0.x, including), and on real devices too.
The time it took on my device (Galaxy S3 with custom rom of Android 5.1) is 1375-2012 ms (on 197 apps total) compared to 37-65 ms using the official way .
EDIT: people claim here that it's not fixed on Android 5.1 . I hope that it got fixed on Android 6 .
This exception is kind of difficult to reproduce under normal circumstances. You will get this exception when there IPC memory is exhausted when transferring data. This can occur in both cases, where a service is trying to place data to client or a client is sending data to service. Most probably some of your users might have installed huge number of application, which results in a data size greater than 1MB (which is the size of IPC buffer).
I am afraid in this case, you will not be do anything better. But if you are doing something like, applyBatch, you can separate one large transaction to multiple smaller transactions.
Also have a look at this thread What to do on TransactionTooLargeException

Categories

Resources