Android Crash优化
异常捕获分析
Java 异常捕获
如果java层抛出了异常并且没有捕获的话,JVM将调用Thread类中的dispatchUncaughtException
/**
* Dispatch an uncaught exception to the handler. This method is
* intended to be called only by the runtime and by tests.
*
* @hide
*/
// Android-changed: Make dispatchUncaughtException() public, for use by tests.
public final void dispatchUncaughtException(Throwable e) {
// BEGIN Android-added: uncaughtExceptionPreHandler for use by platform.
Thread.UncaughtExceptionHandler initialUeh =
Thread.getUncaughtExceptionPreHandler();
if (initialUeh != null) {
try {
initialUeh.uncaughtException(this, e);
} catch (RuntimeException | Error ignored) {
// Throwables thrown by the initial handler are ignored
}
}
// END Android-added: uncaughtExceptionPreHandler for use by platform.
getUncaughtExceptionHandler().uncaughtException(this, e);
}
/**
* Returns the handler invoked when this thread abruptly terminates
* due to an uncaught exception. If this thread has not had an
* uncaught exception handler explicitly set then this thread's
* <tt>ThreadGroup</tt> object is returned, unless this thread
* has terminated, in which case <tt>null</tt> is returned.
* @since 1.5
* @return the uncaught exception handler for this thread
*/
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : group;
}
可以看到这里的处理逻辑是如果存在PreHandler则将异常交给PreHandler处理,如果没有则再看Thread中有没有设置ExceptionHandler,如果设置了则交给这个Handler处理,如果没有设置则交给ThreadGroup去处理
/**
* Called by the Java Virtual Machine when a thread in this
* thread group stops because of an uncaught exception, and the thread
* does not have a specific {@link Thread.UncaughtExceptionHandler}
* installed.
* <p>
* The <code>uncaughtException</code> method of
* <code>ThreadGroup</code> does the following:
* <ul>
* <li>If this thread group has a parent thread group, the
* <code>uncaughtException</code> method of that parent is called
* with the same two arguments.
* <li>Otherwise, this method checks to see if there is a
* {@linkplain Thread#getDefaultUncaughtExceptionHandler default
* uncaught exception handler} installed, and if so, its
* <code>uncaughtException</code> method is called with the same
* two arguments.
* <li>Otherwise, this method determines if the <code>Throwable</code>
* argument is an instance of {@link ThreadDeath}. If so, nothing
* special is done. Otherwise, a message containing the
* thread's name, as returned from the thread's {@link
* Thread#getName getName} method, and a stack backtrace,
* using the <code>Throwable</code>'s {@link
* Throwable#printStackTrace printStackTrace} method, is
* printed to the {@linkplain System#err standard error stream}.
* </ul>
* <p>
* Applications can override this method in subclasses of
* <code>ThreadGroup</code> to provide alternative handling of
* uncaught exceptions.
*
* @param t the thread that is about to exit.
* @param e the uncaught exception.
* @since JDK1.0
*/
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
parent.uncaughtException(t, e);
} else {
Thread.UncaughtExceptionHandler ueh =
Thread.getDefaultUncaughtExceptionHandler();
if (ueh != null) {
ueh.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
System.err.print("Exception in thread \""
+ t.getName() + "\" ");
e.printStackTrace(System.err);
}
}
}
ThreadGroup中的处理逻辑是
父线程组能处理则交给父线程组处理
否则尝试利用一个默认的defaultUncaughtExceptionHandler来处理异常,
而这个defaultUncaughtExceptionHandler是Thread类的一个静态变量,会在android系统启动时由RuntimeInit类初始化为KillApplicationHandler
public static final void main(String[] argv) {
enableDdms();
if (argv.length == 2 && argv[1].equals("application")) {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application");
redirectLogStreams();
} else {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting tool");
}
//在commonInit里
commonInit();
/*
* Now that we're running in interpreted code, call back into native code
* to run the system.
*/
nativeFinishInit();
if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
}
@UnsupportedAppUsage
protected static final void commonInit() {
if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
/*
* set handlers; these apply to all threads in the VM. Apps can replace
* the default handler, but not the pre handler.
*/
LoggingHandler loggingHandler = new LoggingHandler();
RuntimeHooks.setUncaughtExceptionPreHandler(loggingHandler);
Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));
initialized = true;
}
KillApplicationHandler对异常的处理方式是首先调用AMS提供的服务通过DropBox将crash信息存入磁盘,然后再杀掉app的进程
总结一下
如果java层抛出了异常并且没有被捕获的话,JVM将调用Thread类中的dispatchUncaughtException来处理异常,接下来会看Thread类是否有设置异常处理的handler来处理这个异常,如果没有则交给ThreadGroup来处理,ThreadGroup会先尝试交给父ThreadGroup来处理,如果无法处理则交给Thread类的一个静态变量defaultUncaughtExceptionHandler来处理,一般我们没有专门设置的话异常就会交给这个Handler来处理,这个defaultUncaughtExceptionHandler会在android系统启动时在RuntimeInit类初始化时初始化为KillApplicationHandler的实例,KillApplicationHandler对异常的处理方式为首先调用AMS提供的服务通过DropBox将crash信息存入磁盘,然后再杀掉app的进程
Java Exception捕获库
地址:https://github.com/OkAndGreat/CrashDecter
使用
默认提供了四种发生异常时的处理策略:
从上到下依次为重启app,返回到MainActivity,啥也不做和杀死当前抛出异常的Activity
当然也可以实现ICrashStrategy自己去自定义策略
CrashListener是当捕捉到异常后提供给使用者的回调接口
原理分析
从init开始分析
fun init(ctx: Application, strategy: ICrashStrategy, listener: CrashListener?) {
LifecycleCallback.init(ctx)
ActivityLifeCycleCrashHandler.install(ctx, listener)
mContext = ctx
crashListener = listener
crashStrategy = strategy
Thread.setDefaultUncaughtExceptionHandler(this)
}
逐行进行分析
object LifecycleCallback : Application.ActivityLifecycleCallbacks by noOpDelegate() {
fun init(application: Application){
application.registerActivityLifecycleCallbacks(this)
}
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
ActivityCrashManager.addActivity(activity)
}
override fun onActivityDestroyed(activity: Activity) {
ActivityCrashManager.removeActivity(activity)
}
}
LifecycleCallback是为了维护一个Activity的栈,以供发生异常时的处理策略使用:
object ActivityCrashManager {
private val activityStack: Stack<Activity> by lazy {
Stack<Activity>()
}
fun addActivity(activity: Activity) {
activityStack.add(activity)
}
fun removeActivity(activity: Activity) {
activityStack.remove(activity)
}
fun killTopActivity() {
val a = activityStack.pop()
a.finish()
}
fun backToMainActivity() {
while (activityStack.size > 1) {
val a = activityStack.pop()
a.finish()
}
}
}
再看到ActivityLifeCycleCrashHandler
fun install(ctx: Context, listener: CrashListener?) {
if (mInstalled) {
return
}
try {
Reflection.unseal(ctx)
} catch (t: Throwable) {
t.printStackTrace()
}
mInstalled = true
mCrashListener = listener
initActivityKiller()
}
private fun initActivityKiller() {
if (Build.VERSION.SDK_INT >= 28) {
mActivityKiller = ActivityKillerV28()
} else if (Build.VERSION.SDK_INT >= 26) {
mActivityKiller = ActivityKillerV26()
} else if (Build.VERSION.SDK_INT == 25 || Build.VERSION.SDK_INT == 24) {
mActivityKiller = ActivityKillerV24_V25()
} else if (Build.VERSION.SDK_INT <= 23) {
mActivityKiller = ActivityKillerV21_V23()
}
try {
hookmH()
} catch (e: Throwable) {
e.printStackTrace()
}
}
主要是初始化了ActivityKiller,然后hook ActivityThread中的mH然后对Activity的生命周期进行异常监听,如果发生了异常则kill这个Activity,因为不同版本的AOSP源码不同导致了需要对杀死Activity的方法做调整因此有了好几个ActivityKiller
然后在对Thread的DefaultUncaughtExceptionHandler设置成了CrashHandler,通过上面的分析可知当发生异常时会走到CrashHandler的uncaughtException,实现为:
override fun uncaughtException(t: Thread, e: Throwable) {
crashListener?.onExceptionCaught(e)
crashStrategy.onExceptionHappened(mContext)
ActivityLifeCycleCrashHandler.onExceptionCaught(t, e)
}
就是回调了一些接口