6.7.2 AMS的handleApplicationCrash分析
AMS handleApplicationCrash函数的代码如下:
[—>ActivityManagerService.java:handleApplicationCrash]
public void handleApplicationCrash(IBinder app,
ApplicationErrorReport.CrashInfo crashInfo){
//找到对应的ProcessRecord信息,后面那个字符串“Crash”用于打印输出
ProcessRecord r=findAppProcess(app,"Crash");
final String processName=app==null?"system_server"
:(r==null?"unknown":r.processName);
//添加crash信息到dropbox中
ddErrorToDropBox("crash",r, processName, null, null, null, null, null,
crashInfo);
//调用crashApplication函数
crashApplication(r, crashInfo);
}
上述代码中的crashApplication函数的代码如下:
[—>ActivityManagerService.java:crashApplication]
private void crashApplication(ProcessRecord r,
ApplicationErrorReport.CrashInfo crashInfo){
long timeMillis=System.currentTimeMillis();
//从应用进程传递过来的crashInfo中获取相关信息
String shortMsg=crashInfo.exceptionClassName;
String longMsg=crashInfo.exceptionMessage;
String stackTrace=crashInfo.stackTrace;
if(shortMsg!=null&&longMsg!=null){
longMsg=shortMsg+":"+longMsg;
}else if(shortMsg!=null){
longMsg=shortMsg;
}
AppErrorResult result=new AppErrorResult();
synchronized(this){
if(mController!=null){
//通知监视者。目前仅MonkeyTest中会为AMS设置监听者。测试过程中可设定是否一检测
//到App Crash即停止测试。另外,Monkey测试也会将App Crash信息保存起来
//供开发人员分析
}
final long origId=Binder.clearCallingIdentity();
if(r!=null&&r.instrumentationClass!=null){
……//instrumentationClass不为空的情况
}
//①调用makeAppCrashingLocked处理,如果返回false,则整个处理流程完毕
if(r==null||!makeAppCrashingLocked(r, shortMsg, longMsg,
stackTrace)){
……return;
}
Message msg=Message.obtain();
msg.what=SHOW_ERROR_MSG;
HashMap data=new HashMap();
data.put("result",result);
data.put("app",r);
msg.obj=data;
//发送SHOW_ERROR_MSG消息给mHandler,默认处理是弹出一个对话框,提示用户某进程
//崩溃(Crash),用户可以选择“退出”或“退出并报告”
mHandler.sendMessage(msg);
……
}//synchronized(this)结束
//下面这个get函数是阻塞的,直到用户处理了对话框为止。注意,此处涉及两个线程:
//handleApplicationCrash函数是在Binder调用线程中处理的,而对话框则是在mHandler所
//在线程中处理的
int res=result.get();
Intent appErrorIntent=null;
synchronized(this){
if(r!=null)
mProcessCrashTimes.put(r.info.processName, r.info.uid,
SystemClock.uptimeMillis());
if(res==AppErrorDialog.FORCE_QUIT_AND_REPORT)
//createAppErrorIntentLocked返回一个Intent,该Intent的Action是
//"android.intent.action.APP_ERROR",指定接收者是app.errorReportReceiver
//成员,该成员变量在关键点makeAppCrashingLocked中被设置
appErrorIntent=createAppErrorIntentLocked(r, timeMillis,
crashInfo);
}//synchronized(this)结束
if(appErrorIntent!=null){
try{//启动能处理APP_ERROR的应用进程,目前的源码中还没有地方处理它
mContext.startActivity(appErrorIntent);
}……
}
}
以上代码中还有一个关键函数makeAppCrashingLocked,其代码如下:
[—>ActivityManagerService.java:makeAppCrashingLocked]
private boolean makeAppCrashingLocked(ProcessRecord app,
String shortMsg, String longMsg, String stackTrace){
app.crashing=true;
//生成一个错误报告,存放在crashingReport变量中
app.crashingReport=generateProcessError(app,
ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg,
longMsg, stackTrace);
/*
在上边代码中,我们知道系统会通过APP_ERROR Intent启动一个Activity去处理错误报告,
实际上在此之前,系统需要为它找到指定的接收者(如果有)。代码在startAppProblemLocked
中,此处简单描述该函数的处理过程如下:
1.先查询Settings Secure表中“send_action_app_error”是否使能,如果没有使能,则
不能设置指定接收者
2.通过PKMS查询安装此Crash应用的应用是否能接收APP_ERROR Intent。必须注意
安装此应用的应用(例如通过“安卓市场”安装了该Crash应用)。如果没有,则转下一步处理
3.查询系统属性“ro.error.receiver.system.apps”是否指定了APP_ERROR处理者,如果
没有,则转下一步处理
4.查询系统属性“ro.error.receiver.default”是否指定了默认的处理者
5.处理者的信息保存在app的errorReportReceiver变量中
另外,如果该Crash应用正好是串行广播发送处理中的一员,则需要结束它的处理流程以
保证后续广播处理能正常执行。读者可参考skipCurrentReceiverLocked函数
*/
startAppProblemLocked(app);
app.stopFreezingAllLocked();
//调用handleAppCrashLocked做进一步处理。读者可自行阅读
return handleAppCrashLocked(app);
}
当App的Crash处理完后,事情并未就此结束,因为该应用进程退出后,之前AMS为它设置的讣告接收对象将被唤醒。接下来介绍AppDeathRecipient binderDied的处理流程。