Android Fk:【Stability】应用FC弹窗流程
一.概述
在Android手机里,用户可见的应用crash有两种情况:
- 出错后弹出出错提示框
- 应用直接闪退
二.应用FC退出流程
应用进程FC异常分为Java异常FC,Native异常FC
2.1 Java FC Crash弹窗流程
image.png这里注意到调用AMS方法时是同步binder call,因此会在dialog show出来处理完毕后才会走回来kill 自己.
//frameworks/base/services/core/java/com/android/server/am/AppErrors.java
void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,
int callingPid, int callingUid) {
synchronized (mService) {
final Message msg = Message.obtain();
msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG;
task = data.task;
msg.obj = data;
mService.mUiHandler.sendMessage(msg);
}
int res = result.get();//这里会等待dialog处理,主动wait()
...
}
//frameworks/base/services/core/java/com/android/server/am/AppErrorResult.java
final class AppErrorResult {
public void set(int res) {
synchronized (this) {
mHasResult = true;
mResult = res;
notifyAll();
}
}
public int get() {
synchronized (this) {
while (!mHasResult) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mResult;
}
boolean mHasResult = false;
int mResult;
}
2.2 Native FC Crash弹窗流程
image.png弹窗退出方式即便进程是在后台,还是会show出dialog,用户是可以察觉的.
2.3 应用闪退
看下RuntimeInit.java中的code,在commitInit()中设置了两个UncaughtExceptionHandler,其中setUncaughtExceptionPreHandler()不是公开的接口,setDefaultUncaughtExceptionHandler()是公开的接口.
//frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
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.
*/
Thread.setUncaughtExceptionPreHandler(new LoggingHandler());
Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler());
}
这里设置了Thread默认的UncaughtExceptionHandler为KillApplicationHandler:
/**
* Handle application death from an uncaught exception. The framework
* catches these for the main threads, so this should only matter for
* threads created by applications. Before this method runs,
* {@link LoggingHandler} will already have logged details.
*/
private static class KillApplicationHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
try {
...
//这里跨进程去通知AMS show dialog,同步binder call,会等待dialog处理结束(即dismiss掉)再回来
ActivityManager.getService().handleApplicationCrash(
mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
} catch (Throwable t2) {
...
} finally {
// 最后kill掉自己并退出
Process.killProcess(Process.myPid());
System.exit(10);
}
}
}
可以看出KillApplicationHandler在kill自己退出之前会去先同步binder调用show error dialog;
而setDefaultUncaughtExceptionHandler是公开的接口,应用可以自己重写UncaughtExceptionHandler,然后调用Thread.setDefaultUncaughtExceptionHandler()来设置default为重写的handler,从而实现异常时自己需要处理的操作,比如抓取特定的log保存待上传等.
一般良心应用的操作,在application初始化的时候先获取保存默认的UncaughtExceptionHandler,再设置default为重写的UncaughtExceptionHandler,等异常时先调用重写的UncaughtExceptionHandler,等自己的逻辑走完后再调用保存的原来的UncaughtExceptionHandler走系统默认的处理方式.
比如讯飞语音的操作:
public class d implements UncaughtExceptionHandler {
private static d c;
private UncaughtExceptionHandler a;
private Context b;
private d(Context context) {
if (Thread.getDefaultUncaughtExceptionHandler() != this) {
//将默认的UncaughtExceptionHandler保存在a中
this.a = Thread.getDefaultUncaughtExceptionHandler();
//设置默认的为复写后的
Thread.setDefaultUncaughtExceptionHandler(this);
this.b = context.getApplicationContext();
}
}
private String a(Throwable th) {
String str = null;
if (th != null) {
try {
Writer stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
th.printStackTrace(printWriter);
printWriter.close();
str = stringWriter.toString();
} catch (Exception e) {
e.printStackTrace();
}
}
return str;
}
//该方法猜测应该是在讯飞应用application中进行实例化
public static void a(Context context) {
if (c == null) {
c = new d(context);
}
}
public void uncaughtException(Thread thread, Throwable th) {
//先处理自己的逻辑
if (a.h.booleanValue()) {
String a = a(th);
c cVar = new c();
cVar.a = a.d;
cVar.b = e.a(a);
cVar.c = System.currentTimeMillis();
f.a(cVar);
}
new com.iflytek.sunflower.d.d(this.b).a();
if (this.a != null) {
//再调用系统原来默认的,如果前面没有kill掉自己,在这里会走系统原生的killApplicationHandler
//从而会弹出FC dialog.
this.a.uncaughtException(thread, th);
}
}
}
如果进程在后台不可见,该退出方式用户是察觉不到的.
http://blog.csdn.net/TaylorPotter/article/details/79305155
三. 应用进程启动
应用进程会在启动时去设置DefaultUncaughtExceptionHandler,而DefaultUncaughtExceptionHandler是可以复写重新设置的.
简单图:
四. 总结
-
Java FC 弹窗详细流程
image.png -
Native FC 弹窗详细流程
image.png -
应用启动详细流程
image.png -
以上流程图的uml代码
百度云下载上面图中的uml代码
网友评论