-
Notifications
You must be signed in to change notification settings - Fork 42
Android(7): Crash及ANR捕捉上报
clarkehe edited this page Aug 10, 2016
·
2 revisions
Crash的捕捉有助于监控程序Crash率,同时通过捕捉Crash的堆栈信息来定位问题并修复。 Android中捕捉异常信息,通过系统提示的接口就可以了。代码大概如下:
public class CatchCrash {
private final static String TAG = "CatchCrash";
private static Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler;
public static void catchUnhandledException(){
defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new CustomUncaughtExceptionHandler());
}
private static class CustomUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread thread, Throwable ex) {
Log.e(TAG, "***-------------");
ex.printStackTrace();
Log.e(TAG, "uncaughtException, thread:" + thread.getName() + ", ex:" + ex.toString());
Log.e(TAG, "***-------------");
defaultUncaughtExceptionHandler.uncaughtException(thread, ex);
}
}
}
我们写一段代码,故意制造Crash, 就可以看到打印的日志信息,在实际项目,需要这些信息和其他的一些信息一起打包上报到Crash平台。
findViewById(R.id.makeCrashBut).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
String test = null;
Log.d("test", "" + test.length());
}
}).start();
}
08-10 20:34:53.758 15317-15457/com.sample E/CatchCrash: ***-------------
08-10 20:34:53.759 15317-15457/com.sample W/System.err: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference
08-10 20:34:53.760 15317-15457/com.sample W/System.err: at com.sample.crashreport.TestCrashActivity$2$1.run(TestCrashActivity.java:32)
08-10 20:34:53.760 15317-15457/com.sample W/System.err: at java.lang.Thread.run(Thread.java:818)
08-10 20:34:53.761 15317-15457/com.sample E/CatchCrash: uncaughtException, thread:Thread-11103, ex:java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference
08-10 20:34:53.761 15317-15457/com.sample E/CatchCrash: ***-------------
根据Java异常的处理逻辑,代码没有catch处理的异常,最后都会由线程的默认UncaughtExceptionHandler进行处理。如果我们用try_catch将上面产生的异常的代码包住,则程序就不会输出上面的异常信息了。
这个默认的UncaughtExceptionHandler是一个静态变量,应该是进程初始化时设置的,所有线程共享。另外看代码,每个线程还有一个私有的UncaughtExceptionHandler,默认值是null,需要自己进行设置。
/**
* Holds the handler for uncaught exceptions in this Thread,
* in case there is one.
*/
private UncaughtExceptionHandler uncaughtHandler;
/**
* Holds the default handler for uncaught exceptions, in case there is one.
*/
private static UncaughtExceptionHandler defaultUncaughtHandler;
如果设置了私有的UncaughtExceptionHandler,静态UncaughtExceptionHandler则不会生效。
经过调试发现,线程默认的异常处理是由一个叫class com.android.internal.os.RuntimeInit$UncaughtHandler【源码】的类实现的。它的处理逻辑是首先输出相关的异常信息,弹出一个对话框让用户确认,对话框消失后,结束进程。
private static class UncaughtHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
try {
// Don't re-enter -- avoid infinite loops if crash-reporting crashes.
if (mCrashing) return;
mCrashing = true;
if (mApplicationObject == null) {
Slog.e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
} else {
StringBuilder message = new StringBuilder();
message.append("FATAL EXCEPTION: ").append(t.getName()).append("\n");
final String processName = ActivityThread.currentProcessName();
if (processName != null) {
message.append("Process: ").append(processName).append(", ");
}
message.append("PID: ").append(Process.myPid());
Slog.e(TAG, message.toString(), e);
}
// Bring up crash dialog, wait for it to be dismissed
ActivityManagerNative.getDefault().handleApplicationCrash(
mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
} catch (Throwable t2) {
try {
Slog.e(TAG, "Error reporting crash", t2);
} catch (Throwable t3) {
// Even Slog.e() fails! Oh well.
}
} finally {
// Try everything to make sure this process goes away.
Process.killProcess(Process.myPid());
System.exit(10);
}
}
}
ANR是反应系统流畅度的,ANR的发生一定程度影响了用户的体验。ANR也是需要监控的指标。