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的处理流程。