crash日志分类:
- JVM异常(Exception)堆栈信息
- native代码崩溃日志
Java中异常分两种:
检查异常
在代码编译时期,AS会提示代码有错误,无法通过编译,IOException。如果直接抛出则也会导致崩溃
非检查异常
AS不会在编译时期提示这些异常信息,而是在程序运行时期因为代码错误而直接导致崩溃,例如OOM或空指针异常,包含:
对于上述两种异常,都可以使用UncaughtExceptionHandler来进行捕获,他是Thread的一个内部接口
@FunctionalInterface
public interface UncaughtExceptionHandler {
/**
* Method invoked when the given thread terminates due to the
* given uncaught exception.
* <p>Any exception thrown by this method will be ignored by the
* Java Virtual Machine.
* @param t the thread
* @param e the exception
*/
void uncaughtException(Thread t, Throwable e);
}
从注释来看,对于传入的Thread,如果因为“未捕获”异常而导致被终止,uncaughtException则会被调用,可以借助他来间接捕获程序异常,并进行异常信息的记录。
自定义类实现UncaughtExceptionHandler接口,并实现uncaughtException方法:
private Context mContext;
private Thread.UncaughtExceptionHandler mDefaultHandler;
public void init(Context context) {
this.mContext = context;
//系统默认UncaughtExceptionHandler
this.mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
//设置改CrashHandler为系统默认的
Thread.setDefaultUncaughtExceptionHandler(this);
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
// 如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, ex);
} else {
Log.e("CrashHandler", "system.exit");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
Log.e(TAG, "error : ", e);
}
restartApp(mContext);
}
}
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
// 使用Toast来显示异常信息
new Thread() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(mContext, "很抱歉,程序出现异常。", Toast.LENGTH_LONG)
.show();
Looper.loop();
}
}.start();
// 收集设备参数信息
collectDeviceInfo(mContext);
// 保存日志文件
String str = saveCrashInfo2File(ex);
return true;
}
需要注意:
一般情况下,在handleException中需要做一下几件事:
当程序中的native代码发生崩溃时,系统会在/data/tombstones/ 目录下保存一份崩溃日志信息。如果是必现的可以直接看日志,如果不是必现的就需要将日志信息保存到设备中,目前使用广泛且成熟的就是Google的BreakPad。
可以在GitHub上看到介绍文件。我们可以直接使用CMake方式将其编译为一个静态库。在捕获native crash之前,需要初始化BreakPad保存crash日志的路径。
上述介绍的Java和native崩溃的捕获都是基于现场能够复现bug的前提下。但对于线上用户来说不现实。所以一般会使用腾讯的Bugly,Bugly可以满足线上版本捕获crash的所有需求,包括Java层和native层的crash。
除了Bugly外,还有其他的工具,比如XCrash和Sentry。这两者比Bugly好的地方就是除了自动拦截界面崩溃事件,还可以主动上报错误信息,设置过滤条件,使用更加灵活。