深入理解Android Crash 流程
和你一起终身学习,这里是程序员Android
经典好文推荐,通过阅读本文,您将收获以下知识点:
一、Crash 概述
二、Crash处理流程
三、handleApplicationCrash处理分析
四、handleApplicationCrashInner 处理分析
五、APP Error info分析
六、makeAppCrashingLocked处理分析
七、startAppProblemLocked处理分析
八、stopFreezingAllLocked处理分析九、 AppErrors.handleAppCrashLocked()
十、UIHandler
十一、 killProcess
十二、小结
Android 9.0 Crash 机制调用链
/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
/frameworks/base/core/java/android/app/ActivityManagerNative.java (含内部类AMP)
/frameworks/base/core/java/android/app/ApplicationErrorReport.java/frameworks/base/services/core/java/com/android/server/- am/ActivityManagerService.java- am/ProcessRecord.java- am/ActivityRecord.java- am/ActivityStackSupervisor.java- am/ActivityStack.java- am/ActivityRecord.java- am/BroadcastQueue.java- wm/WindowManagerService.java/libcore/libart/src/main/java/java/lang/Thread.java
一、Crash 概述
App Crash (全称Application Crash
), 对于Crash
可分为Native Crash和 Framework Crash(包含app crash在内),对于Crash
相信很多app开发者都会遇到,那么上层什么时候会出现Crash呢,系统又是如何处理Crash
的呢。例如,在app大家经常使用try...catch
语句,那么如果没有有效catch exception
,就是导致应用Crash,发生没有catch exception
,系统便会来进行捕获,并进入Crash
流程。如果你是从事Android系统开发或者架构相关工作,或者遇到需要解系统性的疑难杂症,那么很有必要了解系统Crash
处理流程,知其然还需知其所以然;如果你仅仅是App初级开发,可能本文并非很适合阅读,整个系统流程错综复杂。
在Android系统启动系列文章,已讲述过上层应用都是由Zygote fork孵化而来,分为system_server系统进程和各种应用进程,在这些进程创建之初会设置未捕获异常的处理器,当系统抛出未捕获的异常时,最终都交给异常处理器。
对于
system_server
进程:system_server
启动过程中由RuntimeInit.java
的commonInit
方法设置UncaughtHandler
,用于处理未捕获异常;对于普通应用进程:进程创建过程中,同样会调用
RuntimeInit.java
的commonInit
方法设置UncaughtHandler
。
1.1 crash调用链
crash流程的方法调用关系如下:
AMP.handleApplicationCrashAMS.handleApplicationCrashAMS.findAppProcessAMS.handleApplicationCrashInnerAMS.addErrorToDropBoxAMS.crashApplicationAMS.makeAppCrashingLockedAMS.startAppProblemLockedProcessRecord.stopFreezingAllLockedActivityRecord.stopFreezingScreenLockedWMS.stopFreezingScreenLockedWMS.stopFreezingDisplayLockedAMS.handleAppCrashLockedmUiHandler.sendMessage(SHOW_ERROR_MSG)Process.killProcess(Process.myPid());
System.exit(10);
二、Crash处理流程
RuntimeInit.java
类的 main
方法会调用commonInit()
方法。
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");}// AP Crash 处理流程初始化commonInit();// Native Crash 处理流程初始化nativeFinishInit();if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");}
那么接下来以commonInit()
方法为起点来展开说明。
1. RuntimeInit.commonInit
RuntimeInit.java
protected static final void commonInit() {/** 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();// app不能 替换 setUncaughtExceptionPreHandlerThread.setUncaughtExceptionPreHandler(loggingHandler);// 将异常处理器handler对象赋给Thread成员变量,Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));... ...}
接下来我们看看LoggingHandler
的实现。LoggingHandler实现 Thread.UncaughtExceptionHandler 方法。
private static class LoggingHandler implements Thread.UncaughtExceptionHandler {public volatile boolean mTriggered = false;@Overridepublic void uncaughtException(Thread t, Throwable e) {mTriggered = true;//保证crash处理过程不会重入if (mCrashing) return;//mApplicationObject等于null,一定不是普通的app进程. //但是除了system进程, 也有可能是shell进程, //即通过app_process + 命令参数 的方式创建的进程.if (mApplicationObject == null && (Process.SYSTEM_UID == Process.myUid())) { //系统 进程Crash打印的Log 信息/**发生 系统Crash 时候可以搜索 关键字 FATAL EXCEPTION IN SYSTEM PROCESS**/Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);} else {/**发生 APP Crash 时候可以搜索 关键字 FATAL EXCEPTION**/StringBuilder message = new StringBuilder();message.append("FATAL EXCEPTION: ").append(t.getName()).append("\n");final String processName = ActivityThread.currentProcessName();if (processName != null) {message.append("Process: ").append(processName).append(", ");}message.append("PID: ").append(Process.myPid());Clog_e(TAG, message.toString(), e);}}}
1.当System进程Crash的信息:
开头 FATAL EXCEPTION IN SYSTEM PROCESS [线程名],接着输出Crash
时的调用栈信息;
2.当app进程Crash时的信息:
开头 FATAL EXCEPTION: [线程名],紧接着 Process: [进程名], PID: [进程id]
;最后输出发生Crash
时的调用栈信息。
看到这里,你就会发现要从log
中搜索Crash
信息,只需要搜索关键词 FATAL EXCEPTION,即可查看出是那种异常;如果需要进一步筛选只搜索系统crash信息,则可以搜索的关键词可以有多样,比如 FATAL EXCEPTION IN SYSTEM PROCESS。
当输出完Crash
信息到logcat
里面,这只是Crash
流程的刚开始阶段,接下来弹出Crash
对话框,ActivityManagerNative.getDefault()
返回的是ActivityManagerProxy(简称AMP)
,AMP
经过binder
调用最终交给ActivityManagerService(简称AMS)
中相应的方法去处理,然后调用的是AMS.handleApplicationCrash()
。
分析完LoggingHandler
后,我们继续看setDefaultUncaughtExceptionHandler()
,它只是将异常处理器handler
对象赋给Thread
成员变量,即Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));
。接下来看看KillApplicationHandler
对象实例化过程。
2. KillApplicationHandler
RuntimeInit.java
KillApplicationHandler
实现 Thread.UncaughtExceptionHandler
方法,主要处理由于未捕获的异常Crash
导致APP 崩溃,运行在Main Thread
的Framework
代码会捕获这些异常。
KillApplicationHandler
方法需要传递一个LoggingHandler
的参数,
既 LoggingHandler loggingHandler = new LoggingHandler();
,LoggingHandler
在上文已经分析过,接下来我们看看KillApplicationHandler
方法.
KillApplicationHandler方法如下:
private static class KillApplicationHandler implements Thread.UncaughtExceptionHandler {private final LoggingHandler mLoggingHandler;public KillApplicationHandler(LoggingHandler loggingHandler) {// 构造方法,初始化 loggingHandler this.mLoggingHandler = Objects.requireNonNull(loggingHandler);}@Overridepublic void uncaughtException(Thread t, Throwable e) {try {ensureLogging(t, e);// 保证crash处理过程不会重入if (mCrashing) return;mCrashing = true;... ...//启动crash对话框,等待处理完成 【见小节2.1和3】ActivityManager.getService().handleApplicationCrash(mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));} catch (Throwable t2) {... ... } finally {//确保当前进程彻底杀掉【见小节11】Process.killProcess(Process.myPid());System.exit(10);}}... ...
}
接下来我们看看启动Crash
弹窗的处理。new ApplicationErrorReport.ParcelableCrashInfo(e)
方法。
2.1 ApplicationErrorReport.ParcelableCrashInfo
ApplicationErrorReport 主要用来描述 APP Error
信息。
APP ERROR 信息分类如下:
TYPE_CRASH:APP Crash 信息
TYPE_ANR:APP ANR 信息
TYPE_BATTERY:Battery 使用信息
TYPE_RUNNING_SERVICE:正在运行的Service 相关信息
// 主要处理 APP Error 信息
public class ApplicationErrorReport implements Parcelable {... ...public static class ParcelableCrashInfo extends CrashInfo implements Parcelable {//创建 CrashInfo 实例,初始化异常信息public ParcelableCrashInfo(Throwable tr) {super(tr);}... ... public static final Parcelable.Creator<ParcelableCrashInfo> CREATOR =new Parcelable.Creator<ParcelableCrashInfo>() {@Overridepublic ParcelableCrashInfo createFromParcel(Parcel in) {return new ParcelableCrashInfo(in);}@Overridepublic ParcelableCrashInfo[] newArray(int size) {return new ParcelableCrashInfo[size];}};}... ...
}
ParcelableCrashInfo
继承 CrashInfo
,接下来我们看看 CrashInfo
的实现。
CrashInfo
**CrashInfo ** 主要是将Crash
信息文件名,类名,方法名,对应行号以及异常信息都封装到CrashInfo
对象。
// 描述 Crash 信息public static class CrashInfo {... ...public CrashInfo() {}//CrashInfo 初始化实例 public CrashInfo(Throwable tr) {StringWriter sw = new StringWriter();PrintWriter pw = new FastPrintWriter(sw, false, 256);//输出栈tracetr.printStackTrace(pw);pw.flush();stackTrace = sanitizeString(sw.toString());exceptionMessage = tr.getMessage();// 显示异常的根本原因Throwable rootTr = tr;while (tr.getCause() != null) {tr = tr.getCause();if (tr.getStackTrace() != null && tr.getStackTrace().length > 0) {rootTr = tr;}String msg = tr.getMessage();if (msg != null && msg.length() > 0) {exceptionMessage = msg;}}// Crash 异常类名称 exceptionClassName = rootTr.getClass().getName();if (rootTr.getStackTrace().length > 0) {StackTraceElement trace = rootTr.getStackTrace()[0];// 获取 trace 文件名、类名、方法名、Crash 行号throwFileName = trace.getFileName();throwClassName = trace.getClassName();throwMethodName = trace.getMethodName();throwLineNumber = trace.getLineNumber();} else {throwFileName = "unknown";... ... }exceptionMessage = sanitizeString(exceptionMessage);}
三、handleApplicationCrash处理分析
handleApplicationCrash
会通过 JNI
接口调用AMS
中的方法。
//发送 Crash 弹窗handler,直到Dialog dismissActivityManager.getService().handleApplicationCrash(mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
ActivityManagerService.java
handleApplicationCrash
通过JNI
回调用 AMS
中的handleApplicationCrash
方法,进而调用AMS
中的内部方法handleApplicationCrashInner
。
handleApplicationCrash
1.当远程
IBinder
对象为空Null
时,则进程名为system_server
;2.当远程
IBinder
对象不为空,且ProcessRecord
为空时,则进程名为unknown
;3.当远程
IBinder
对象不为空,且ProcessRecord
不为空时,则进程名为ProcessRecord
对象中相应进程名。
// 当app Crash 时候,会调用此方法。//调用结束后 ,app 进程就会推出public void handleApplicationCrash(IBinder app,ApplicationErrorReport.ParcelableCrashInfo crashInfo) {// findAppProcess 详见 3.1 分析ProcessRecord r = findAppProcess(app, "Crash");// system_server 进程 为Null final String processName = app == null ? "system_server": (r == null ? "unknown" : r.processName);//handleApplicationCrashInner 详见 4 分析handleApplicationCrashInner("crash", r, processName, crashInfo);}
handleApplicationCrashInner
主要是调用 AppErrors
类中的crashApplication
方法处理。
void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,ApplicationErrorReport.CrashInfo crashInfo) {... ... //调用APP Error 类方法中的 crashApplicationmAppErrors.crashApplication(r, crashInfo);}
3.1 findAppProcess
ActivityManagerService.java
findAppProcess
主要是通过for
循环遍历查找出IBinder
对应的Process
.
private ProcessRecord findAppProcess(IBinder app, String reason) {... ...synchronized (this) {final int NP = mProcessNames.getMap().size();for (int ip=0; ip<NP; ip++) {SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);final int NA = apps.size();for (int ia=0; ia<NA; ia++) {ProcessRecord p = apps.valueAt(ia);//当找到目标进程则返回if (p.thread != null && p.thread.asBinder() == app) {return p;}}}//如果代码执行到这里,表明无法找到应用所在的进程return null;}}
其中 mProcessNames = new ProcessMap<ProcessRecord>();
对于代码mProcessNames.getMap()
返回的是mMap
,而mMap= new ArrayMap<String, SparseArray<ProcessRecord>>()
;
知识延伸:SparseArray
和ArrayMap
是Android
专门针对内存优化而设计的取代Java API
中的HashMap
的数据结构。
对于key
是int
类型则使用SparseArray
,可避免自动装箱过程;
对于key
为其他类型则使用ArrayMap
。
HashMap
的查找和插入时间复杂度为O(1)
的代价是牺牲大量的内存来实现的,而SparseArray
和ArrayMap
性能略逊于HashMap
,但更节省内存
。
再回到mMap
,这是以进程name
为key
,再以(uid为key,以ProcessRecord为Value的)
结构体作为value
。下面看看其get()
和put()
方法
public E get(String name, int uid) {SparseArray<E> uids = mMap.get(name);if (uids == null) return null;return uids.get(uid);}public E put(String name, int uid, E value) {SparseArray<E> uids = mMap.get(name);if (uids == null) {uids = new SparseArray<E>(2);mMap.put(name, uids);}uids.put(uid, value);return value;}
findAppProcess()
根据app(IBinder类型)
来查询相应的目标对象ProcessRecord
。
有了进程记录对象ProcessRecord
和进程名processName
,则进入执行Crash
处理方法 AppErrors.java
,继续往下看。
四、handleApplicationCrashInner 处理分析
ActivityManagerService.java
void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,ApplicationErrorReport.CrashInfo crashInfo) {... ...//将错误信息追加到DropBoxaddErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);//【见小节5】mAppErrors.crashApplication(r, crashInfo);}
其中addErrorToDropBox
是将Crash
的信息输出到目录/data/system/dropbox
。例如system_server
的dropbox
文件名为system_server_crash@xxx.txt (xxx代表的是时间戳)
五、APP Error info分析
AppErrors.java
AppErrors 主要是 控制APP Crash
的场景条件。
void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {... ...try {// 调用内部 crashApplicationInner方法crashApplicationInner(r, crashInfo, callingPid, callingUid);} finally {Binder.restoreCallingIdentity(origId);}}
crashApplicationInner
内部方法
void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,int callingPid, int callingUid) {... ... AppErrorResult result = new AppErrorResult();TaskRecord task;synchronized (mService) {// 如果是通过IActivityController 实例导致的Crash ,则不显示弹窗// 详见5.1 if (handleAppCrashInActivityController(r, crashInfo, shortMsg, longMsg, stackTrace,timeMillis, callingPid, callingUid)) {return;}... ...AppErrorDialog.Data data = new AppErrorDialog.Data();data.result = result;data.proc = r;// 无法势必的进程 也不显示Crash 弹窗【见小节6】if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, data)) {return;}final Message msg = Message.obtain();msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG;task = data.task;msg.obj = data;//发送消息SHOW_ERROR_MSG,弹出提示crash的对话框,等待用户选择【见小节10】mService.mUiHandler.sendMessage(msg);}//进入阻塞等待,直到用户选择crash对话框"退出"或者"退出并报告"int res = result.get();Intent appErrorIntent = null;MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res);if (res == AppErrorDialog.TIMEOUT || res == AppErrorDialog.CANCEL) {res = AppErrorDialog.FORCE_QUIT;}... ...
}
5.1 handleAppCrashInActivityController
handleAppCrashInActivityController
,通过IActivityController
实例导致的Crash
,则不显示弹窗.
AppError.java
private boolean handleAppCrashInActivityController(ProcessRecord r,ApplicationErrorReport.CrashInfo crashInfo,String shortMsg, String longMsg,String stackTrace, long timeMillis,int callingPid, int callingUid) {... ... // 当存在ActivityController的情况,比如monkeytry {String name = r != null ? r.processName : null;int pid = r != null ? r.pid : callingPid;int uid = r != null ? r.info.uid : callingUid;//调用monkey的 appCrashedif (!mService.mController.appCrashed(name, pid,shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"))&& "Native crash".equals(crashInfo.exceptionClassName)) {Slog.w(TAG, "Skip killing native crashed app " + name+ "(" + pid + ") during testing");} else {Slog.w(TAG, "Force-killing crashed app " + name+ " at watcher's request");if (r != null) {//调用`makeAppCrashingLocked`,继续处理crash流程// 详见 小结 6 if (!makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, null)){r.kill("crash", true);}} else {// Huh.Process.killProcess(pid);ActivityManagerService.killProcessGroup(uid, pid);}}return true;}} catch (RemoteException e) {mService.mController = null;Watchdog.getInstance().setActivityController(null);}return false;}
该方法主要做的两件事:
调用
makeAppCrashingLocked
,继续处理Crash
流程;发送消息
SHOW_ERROR_MSG
,弹出提示Crash
的对话框,等待用户选择;
接下来我们看makeAppCrashingLocked
实现。
六、makeAppCrashingLocked处理分析
AppError.java
private boolean makeAppCrashingLocked(ProcessRecord app,String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {app.crashing = true;//封装crash信息到crashingReport对象app.crashingReport = generateProcessError(app,ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);//【见小节7】startAppProblemLocked(app);//停止屏幕冻结【见小节8】app.stopFreezingAllLocked();//【见小节9】return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace,data);}
七、startAppProblemLocked处理分析
AppError.java
startAppProblemLocked
该方法主要功能:
获取当前用户下的
crash
应用的error receiver
;忽略当前
App
的广播接收;
void startAppProblemLocked(ProcessRecord app) {// 如果不是当前user正在运行 app,这置为空app.errorReportReceiver = null;for (int userId : mService.mUserController.getCurrentProfileIds()) {if (app.userId == userId) {//获取当前用户下的crash应用的error receiver【见小节7.1】app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(mContext, app.info.packageName, app.info.flags);}}//忽略当前app的广播接收【见小节7.2】mService.skipCurrentReceiverLocked(app);}
7.1 getErrorReportReceiver
ApplicationErrorReport.java
获取当前用户下的Crash
应用的error receiver
public static ComponentName getErrorReportReceiver(Context context,String packageName, int appFlags) {//检查Settings中的"send_action_app_error"是否使能错误报告的功能int enabled = Settings.Global.getInt(context.getContentResolver(),Settings.Global.SEND_ACTION_APP_ERROR, 0);if (enabled == 0) {//1.当未使能时,则直接返回return null;}PackageManager pm = context.getPackageManager();// look for receiver in the installer packageString candidate = null;ComponentName result = null;try {//获取该crash应用的安装器的包名candidate = pm.getInstallerPackageName(packageName);} catch (IllegalArgumentException e) {// the package could already removed}if (candidate != null) {result = getErrorReportReceiver(pm, packageName, candidate);if (result != null) {//2.当找到该crash应用的安装器,则返回;return result;}}//该系统属性名为"ro.error.receiver.system.apps"if ((appFlags&ApplicationInfo.FLAG_SYSTEM) != 0) {candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);// 通过上下文对象传参,调用类内部方法result = getErrorReportReceiver(pm, packageName, candidate);if (result != null) {//3.当crash应用是系统应用时,且系统属性指定error receiver时,则返回;return result;}}//该默认属性名为"ro.error.receiver.default"candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);//4.当默认属性值指定error receiver时,则返回;return getErrorReportReceiver(pm, packageName, candidate);}
getErrorReportReceiver:
这是同名不同输入参数的另一个方法:
static ComponentName getErrorReportReceiver(PackageManager pm, String errorPackage,String receiverPackage) {if (receiverPackage == null || receiverPackage.length() == 0) {return null;}//当安装应用程序的安装器Crash,则直接返回if (receiverPackage.equals(errorPackage)) {return null;}//ACTION_APP_ERROR值为"android.intent.action.APP_ERROR"Intent intent = new Intent(Intent.ACTION_APP_ERROR);intent.setPackage(receiverPackage);ResolveInfo info = pm.resolveActivity(intent, 0);if (info == null || info.activityInfo == null) {return null;}//创建包名为receiverPackage的组件return new ComponentName(receiverPackage, info.activityInfo.name);}
7.2 skipCurrentReceiverLocked
ActivityManagerService.java
忽略当前app
的广播接收
void skipCurrentReceiverLocked(ProcessRecord app) {for (BroadcastQueue queue : mBroadcastQueues) {// 会调用BroadcastQueue 中的方法【见小节7.2.1】queue.skipCurrentReceiverLocked(app);}}
7.2.1 skipCurrentReceiverLocked
BroadcastQueue.java
skipCurrentReceiverLocked
忽略当前app的广播接收.
public void skipCurrentReceiverLocked(ProcessRecord app) {BroadcastRecord r = null;//查看app进程中的广播if (mOrderedBroadcasts.size() > 0) {BroadcastRecord br = mOrderedBroadcasts.get(0);// 判断是否一致if (br.curApp == app) {r = br;}}... ...if (r != null) {// 见7.2.2skipReceiverLocked(r);}}
7.2.2 skipReceiverLocked
BroadcastQueue.java
private void skipReceiverLocked(BroadcastRecord r) {logBroadcastReceiverDiscardLocked(r);//结束app进程的广播结束finishReceiverLocked(r, r.resultCode, r.resultData,r.resultExtras, r.resultAbort, false);//执行广播调度scheduleBroadcastsLocked();}
八、stopFreezingAllLocked处理分析
AppError.java
中的 makeAppCrashingLocked
方法(第6步),会调用stopFreezingAllLocked
方法
ProcessRecord.java
public void stopFreezingAllLocked() {int i = activities.size();while (i > 0) {i--;// 停止进程里所有的`Activity`. 详见8.1 activities.get(i).stopFreezingScreenLocked(true);}}
其中activities
类型为ArrayList<ActivityRecord>
,停止进程里所有的Activity
.
8.1 AR.stopFreezingScreenLocked
ActivityRecord.java
,stopFreezingScreenLocked
停止进程里所有的Activity
.
public void stopFreezingScreenLocked(boolean force) {if (force || frozenBeforeDestroy) {frozenBeforeDestroy = false;// mWindowContainerController 见【8.1.1】mWindowContainerController.stopFreezingScreen(force);}}
8.1.1mWindowContainerController.stopFreezingScreen
stopFreezingScreen.java
public void stopFreezingScreen(boolean force) {synchronized(mWindowMap) {if (mContainer == null) {return;}if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="+ mContainer.isHidden() + " freezing=" + mContainer.isFreezingScreen());mContainer.stopFreezingScreen(true, force);}}
8.1.1.1 WMS.stopFreezingScreenLocked
WindowManagerService.java
@Overridepublic void stopFreezingScreen() {... ...synchronized(mWindowMap) {if (mClientFreezingScreen) {mClientFreezingScreen = false;mLastFinishedFreezeSource = "client";final long origId = Binder.clearCallingIdentity();try {// 详见 8.1.1.2stopFreezingDisplayLocked();} finally {Binder.restoreCallingIdentity(origId);}}}}
8.1.1.2 stopFreezingDisplayLocked();
WindowManagerService.java
该方法主要功能:
处理屏幕旋转相关逻辑;
移除冻屏的超时消息;
屏幕旋转动画的相关操作;
使能输入事件分发功能;
display
冻结时,执行gc
操作;
更新当前的屏幕方向;
向mH
发送configuraion
改变的消息
rivate void stopFreezingDisplayLocked() {if (!mDisplayFrozen) {return; //显示没有冻结,则直接返回}//往往跟屏幕旋转相关...mDisplayFrozen = false;//从上次冻屏到现在的总时长mLastDisplayFreezeDuration = (int)(SystemClock.elapsedRealtime() - mDisplayFreezeTime);//移除冻屏的超时消息mH.removeMessages(H.APP_FREEZE_TIMEOUT);mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);boolean updateRotation = false;//获取默认的DisplayContentfinal DisplayContent displayContent = getDefaultDisplayContentLocked();final int displayId = displayContent.getDisplayId();ScreenRotationAnimation screenRotationAnimation =mAnimator.getScreenRotationAnimationLocked(displayId);//屏幕旋转动画的相关操作if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null&& screenRotationAnimation.hasScreenshot()) {DisplayInfo displayInfo = displayContent.getDisplayInfo();boolean isDimming = displayContent.isDimming();if (!mPolicy.validateRotationAnimationLw(mExitAnimId, mEnterAnimId, isDimming)) {mExitAnimId = mEnterAnimId = 0;}//加载动画最大时长为10sif (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,getTransitionAnimationScaleLocked(), displayInfo.logicalWidth,displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) {scheduleAnimationLocked();} else {screenRotationAnimation.kill();mAnimator.setScreenRotationAnimationLocked(displayId, null);updateRotation = true;}} else {if (screenRotationAnimation != null) {screenRotationAnimation.kill();mAnimator.setScreenRotationAnimationLocked(displayId, null);}updateRotation = true;}//经过层层调用到InputManagerService服务,IMS服务使能输入事件分发功能mInputMonitor.thawInputDispatchingLw();boolean configChanged;//当display被冻结时不再计算屏幕方向,以避免不连续的状态。configChanged = updateOrientationFromAppTokensLocked(false);//display冻结时,执行gc操作mH.removeMessages(H.FORCE_GC);mH.sendEmptyMessageDelayed(H.FORCE_GC, 2000);//mScreenFrozenLock的类型为PowerManager.WakeLock,即释放屏幕冻结的锁mScreenFrozenLock.release();if (updateRotation) {//更新当前的屏幕方向configChanged |= updateRotationUncheckedLocked(false);}if (configChanged) {//向mH发送configuraion改变的消息mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);}
}
九、 AppErrors.handleAppCrashLocked()
AppErrors.java
1.当同一进程在时间间隔小于1分钟
时连续两次Crash
,则执行的情况下:
对于非persistent
进程:
[9.1] mStackSupervisor.handleAppCrashLocked(app);
[9.2] removeProcessLocked(app, false, false, “crash”);
[9.3] mStackSupervisor.resumeTopActivitiesLocked();
对于persistent
进程,则只执行
[9.3] mStackSupervisor.resumeTopActivitiesLocked();
2.否则执行
[9.4] mStackSupervisor.finishTopCrashedActivitiesLocked(app, reason);
boolean handleAppCrashLocked(ProcessRecord app, String reason,String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {final long now = SystemClock.uptimeMillis();final boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;final boolean procIsBoundForeground =(app.curProcState == ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);Long crashTime;Long crashTimePersistent;boolean tryAgain = false;if (!app.isolated) {crashTime = mProcessCrashTimes.get(app.info.processName, app.uid);crashTimePersistent = mProcessCrashTimesPersistent.get(app.info.processName, app.uid);} else {crashTime = crashTimePersistent = null;}// Bump up the crash count of any services currently running in the proc.//运行在当前进程中的所有服务的crash次数操作for (int i = app.services.size() - 1; i >= 0; i--) {// list 所有的ServiceServiceRecord sr = app.services.valueAt(i);// Service 一会自动起来 重置count 为1,否则+1if (now > sr.restartTime + ProcessList.MIN_CRASH_INTERVAL) {sr.crashCount = 1;} else {sr.crashCount++;}// 允许重启正在Crash的服务以及 前台Service,wallpapers 等if (sr.crashCount < mService.mConstants.BOUND_SERVICE_MAX_CRASH_RETRY&& (sr.isForeground || procIsBoundForeground)) {tryAgain = true;}}//当同一个进程,连续两次crash的时间间隔小于1分钟时,则认为crash太过于频繁if (crashTime != null && now < crashTime + ProcessList.MIN_CRASH_INTERVAL) {Slog.w(TAG, "Process " + app.info.processName+ " has crashed too many times: killing!");EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,app.userId, app.info.processName, app.uid);//【见小节9.1】mService.mStackSupervisor.handleAppCrashLocked(app);if (!app.persistent) {//不再重启非persistent进程,除非用户显式地调用EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.userId, app.uid,app.info.processName);if (!app.isolated) {//将当前app加入到mBadProcessesmBadProcesses.put(app.info.processName, app.uid,new BadProcessInfo(now, shortMsg, longMsg, stackTrace));mProcessCrashTimes.remove(app.info.processName, app.uid);}app.bad = true;app.removed = true;//移除非persistent 进程的所有服务,保证不再重启【见小节9.2】mService.removeProcessLocked(app, false, tryAgain, "crash");//恢复最顶部的Activity【见小节9.3】mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();if (!showBackground) {return false;}}mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();} else {//此处reason="force-crash"【见小节9.4】 final TaskRecord affectedTask =mService.mStackSupervisor.finishTopRunningActivityLockedfinishTopRunningActivityLocked(app, reason);if (data != null) {data.task = affectedTask;}if (data != null && crashTimePersistent != null&& now < crashTimePersistent + ProcessList.MIN_CRASH_INTERVAL) {data.repeating = true;}}if (data != null && tryAgain) {data.isRestartableForService = true;}//当桌面Home 进程 应用crash,并且被三方app所取代,那么需要清空桌面应用的偏爱选项。final ArrayList<ActivityRecord> activities = app.activities;if (app == mService.mHomeProcess && activities.size() > 0&& (mService.mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {final ActivityRecord r = activities.get(activityNdx);if (r.isActivityTypeHome()) {Log.i(TAG, "Clearing package preferred activities from " + r.packageName);try {//清空偏爱应用ActivityThread.getPackageManager().clearPackagePreferredActivities(r.packageName);} catch (RemoteException c) {// pm is in same process, this will never happen.}}}}if (!app.isolated) {//无法记录孤立进程的crash时间点,由于他们并没有一个固定身份.mProcessCrashTimes.put(app.info.processName, app.uid, now);mProcessCrashTimesPersistent.put(app.info.processName, app.uid, now);}//当app存在crash的handler,那么交给其处理if (app.crashHandler != null) mService.mHandler.post(app.crashHandler);return true;}
9.1 ASS.handleAppCrashLocked
ActivityStackSupervisor.java
void handleAppCrashLocked(ProcessRecord app) {for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {final ActivityStack stack = display.getChildAt(stackNdx);//调用ActivityStack【见小节9.1.1】stack.handleAppCrashLocked(app);}}}
9.1.1 AS.handleAppCrashLocked
ActivityStack.java
void handleAppCrashLocked(ProcessRecord app) {for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {final ActivityRecord r = activities.get(activityNdx);if (r.app == app) {Slog.w(TAG, " Force finishing activity "+ r.intent.getComponent().flattenToShortString());// Force the destroy to skip right to removal.r.app = null;mWindowManager.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE,false /* alwaysKeepCurrent */);//结束当前activityfinishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false,"handleAppCrashedLocked");}}}}
这里的mTaskHistory
数据类型为ArrayList
,记录着所有先前的后台activities
。遍历所有activities
,找到位于该ProcessRecord
的所有ActivityRecord
,并结束该Acitivity
。
9.2 AMS.removeProcessLocked
ActivityManagerService.java
@GuardedBy("this")boolean removeProcessLocked(ProcessRecord app,boolean callerWillRestart, boolean allowRestart, String reason) {final String name = app.processName;final int uid = app.uid;if (DEBUG_PROCESSES) Slog.d(TAG_PROCESSES,"Force removing proc " + app.toShortString() + " (" + name + "/" + uid + ")");ProcessRecord old = mProcessNames.get(name, uid);if (old != app) {// This process is no longer active, so nothing to do.Slog.w(TAG, "Ignoring remove of inactive process: " + app);return false;}//从mProcessNames移除该进程removeProcessNameLocked(name, uid);if (mHeavyWeightProcess == app) {mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,mHeavyWeightProcess.userId, 0));mHeavyWeightProcess = null;}boolean needRestart = false;if ((app.pid > 0 && app.pid != MY_PID) || (app.pid == 0 && app.pendingStart)) {int pid = app.pid;if (pid > 0) {synchronized (mPidsSelfLocked) {mPidsSelfLocked.remove(pid);mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);}mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);if (app.isolated) {mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);getPackageManagerInternalLocked().removeIsolatedUid(app.uid);}}boolean willRestart = false;//对于非孤立的persistent进程设置成可重启flagsif (app.persistent && !app.isolated) {if (!callerWillRestart) {willRestart = true;} else {needRestart = true;}}// 杀进程【9.2.1】app.kill(reason, true);//移除进程并清空该进程相关联的activity/service等组件 【9.2.2】handleAppDiedLocked(app, willRestart, allowRestart);if (willRestart) {//此处willRestart=false,不进入该分支removeLruProcessLocked(app);addAppLocked(app.info, null, false, null /* ABI override */);}} else {mRemovedProcesses.add(app);}return needRestart;}
mProcessNames
数据类型为ProcessMap
,这是以进程名为key
,记录着所有的ProcessRecord
信息mPidsSelfLocked
数据类型为SparseArray
,这是以pid
为key
,记录着所有的ProcessRecord
信息。该对象的同步保护是通过自身锁,而非全局ActivityManager
锁。
9.2.1 app.kill
ProcessRecord.java]
void kill(String reason, boolean noisy) {//通过am 杀进程if (!killedByAm) {// 如果不想让am kill 当前进程,可以在这地方跳过if (!mService.mAmsExt.shouldKilledByAm(this.processName, reason)) {return;}Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "kill");if (mService != null && (noisy || info.uid == mService.mCurOomAdjUid)) {mService.reportUidInfoMessageLocked(TAG,"Killing " + toShortString() + " (adj " + setAdj + "): " + reason,info.uid);}if (pid > 0) {EventLog.writeEvent(EventLogTags.AM_KILL, userId, pid, processName, setAdj, reason);// pid > 0 杀进程以及所在的进程组Process.killProcessQuiet(pid);ActivityManagerService.killProcessGroup(uid, pid);} else {pendingStart = false;}if (!persistent) {killed = true;killedByAm = true;}Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}}
此处reason为“crash”.
9.2.2 handleAppDiedLocked
ActivityManagerService.java
// 通过AM 移除当前存在的进程,不存在,则清除当前进程包含的所有内容@GuardedBy("this")private final void handleAppDiedLocked(ProcessRecord app,boolean restarting, boolean allowRestart) {int pid = app.pid;final boolean clearLaunchStartTime = !restarting && app.removed && app.foregroundActivities;//清除应用中service/receiver/ContentProvider信息boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1,false /*replacingPid*/);if (!kept && !restarting) {// 根据LRU 算法移除 app 进程removeLruProcessLocked(app);if (pid > 0) {//从list 移除对应的pid ProcessList.remove(pid);}}if (mProfileProc == app) {clearProfilerLocked();}//清除应用中activity相关信息boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(app);app.clearRecentTasks();app.activities.clear();if (app.instr != null) {Slog.w(TAG, "Crash of app " + app.processName+ " running instrumentation " + app.instr.mClass);Bundle info = new Bundle();info.putString("shortMsg", "Process crashed.");finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);}mWindowManager.deferSurfaceLayout();try {if (!restarting && hasVisibleActivities&& !mStackSupervisor.resumeFocusedStackTopActivityLocked()) {// If there was nothing to resume, and we are not already restarting this process, but// there is a visible activity that is hosted by the process... then make sure all// visible activities are running, taking care of restarting this process.mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);}} finally {mWindowManager.continueSurfaceLayout();}// TODO (b/67683350)// When an app process is removed, activities from the process may be relaunched. In the// case of forceStopPackageLocked the activities are finished before any window is drawn,// and the launch time is not cleared. This will be incorrectly used to calculate launch// time for the next launched activity launched in the same windowing mode.if (clearLaunchStartTime) {final LaunchTimeTracker.Entry entry = mStackSupervisor.getLaunchTimeTracker().getEntry(mStackSupervisor.getWindowingMode());if (entry != null) {entry.mLaunchStartTime = 0;}}}
9.3 ASS.resumeFocusedStackTopActivityLocked
ActivityStackSupervisor.java
boolean resumeFocusedStackTopActivityLocked() {return resumeFocusedStackTopActivityLocked(null, null, null);}boolean resumeFocusedStackTopActivityLocked(ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {if (!readyToResume()) {return false;}if (targetStack != null && isFocusedStack(targetStack)) {//【见小节9.3.1】return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);}final ActivityRecord r = mFocusedStack.topRunningActivityLocked();if (r == null || !r.isState(RESUMED)) {mFocusedStack.resumeTopActivityUncheckedLocked(null, null);} else if (r.isState(RESUMED)) {// Kick off any lingering app transitions form the MoveTaskToFront operation.mFocusedStack.executeAppTransition(targetOptions);}return false;}
9.3.1 AS.resumeTopActivityLocked
ActivityStack.java
//确保 top Activity 在resumed 状态// 最好使用ActivityStackSupervisor#ActivityStackSupervisor#resumeFocusedStackTopActivityLockedActivityStackSupervisor#resumeFocusedStackTopActivityLocked 待替此方法boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {if (mStackSupervisor.inResumeTopActivity) {// Don't even start recursing.return false;}boolean result = false;try {// Protect against recursion.mStackSupervisor.inResumeTopActivity = true;result = resumeTopActivityInnerLocked(prev, options);// When resuming the top activity, it may be necessary to pause the top activity (for// example, returning to the lock screen. We suppress the normal pause logic in// {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the// end. We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here// to ensure any necessary pause logic occurs. In the case where the Activity will be// shown regardless of the lock screen, the call to// {@link ActivityStackSupervisor#checkReadyForSleepLocked} is skipped.final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);if (next == null || !next.canTurnScreenOn()) {checkReadyForSleep();}} finally {mStackSupervisor.inResumeTopActivity = false;}return result;}
9.4 finishTopCrashedActivitiesLocked
ActivityStackSupervisor.java
//Finish the topmost activities in all stacks that belong to the crashed appTaskRecord finishTopCrashedActivitiesLocked(ProcessRecord app, String reason) {TaskRecord finishedTask = null;ActivityStack focusedStack = getFocusedStack();for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);// It is possible that request to finish activity might also remove its task and stack,// so we need to be careful with indexes in the loop and check child count every time.for (int stackNdx = 0; stackNdx < display.getChildCount(); ++stackNdx) {final ActivityStack stack = display.getChildAt(stackNdx);此处reason= "force-crash" 见小节9.4.1final TaskRecord t = stack.finishTopCrashedActivityLocked(app, reason);if (stack == focusedStack || finishedTask == null) {finishedTask = t;}}}return finishedTask;}
9.4.1AS.finishTopCrashedActivityLocked
ActivityStack.java
/*** Finish the topmost activity that belongs to the crashed app. We may also finish the activity* that requested launch of the crashed one to prevent launch-crash loop.*/ final TaskRecord finishTopCrashedActivityLocked(ProcessRecord app, String reason) {ActivityRecord r = topRunningActivityLocked();TaskRecord finishedTask = null;if (r == null || r.app != app) {return null;}Slog.w(TAG, " Force finishing activity "+ r.intent.getComponent().flattenToShortString());finishedTask = r.getTask();int taskNdx = mTaskHistory.indexOf(finishedTask);final TaskRecord task = finishedTask;int activityNdx = task.mActivities.indexOf(r);mWindowManager.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE,false /* alwaysKeepCurrent */);// 见小结 9.4.2finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);finishedTask = task;// Also terminate any activities below it that aren't yet// stopped, to avoid a situation where one will get// re-start our crashing activity once it gets resumed again.--activityNdx;if (activityNdx < 0) {do {--taskNdx;if (taskNdx < 0) {break;}activityNdx = mTaskHistory.get(taskNdx).mActivities.size() - 1;} while (activityNdx < 0);}if (activityNdx >= 0) {r = mTaskHistory.get(taskNdx).mActivities.get(activityNdx);if (r.isState(RESUMED, PAUSING, PAUSED)) {if (!r.isActivityTypeHome() || mService.mHomeProcess != r.app) {Slog.w(TAG, " Force finishing activity "+ r.intent.getComponent().flattenToShortString());finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);}}}return finishedTask;}
9.4.2 AS.finishActivityLocked
ActivityStack.java
/*** See {@link #finishActivityLocked(ActivityRecord, int, Intent, String, boolean, boolean)}*/final boolean finishActivityLocked(ActivityRecord r, int resultCode, Intent resultData,String reason, boolean oomAdj) {return finishActivityLocked(r, resultCode, resultData, reason, oomAdj, !PAUSE_IMMEDIATELY);}/*** @return Returns true if this activity has been removed from the history* list, or false if it is still in the list and will be removed later.*/final boolean finishActivityLocked(ActivityRecord r, int resultCode, Intent resultData,String reason, boolean oomAdj, boolean pauseImmediately) {if (r.finishing) {Slog.w(TAG, "Duplicate finish request for " + r);return false;}mWindowManager.deferSurfaceLayout();try {//设置finish状态的activity不可见r.makeFinishingLocked();final TaskRecord task = r.getTask();EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,r.userId, System.identityHashCode(r),task.taskId, r.shortComponentName, reason);final ArrayList<ActivityRecord> activities = task.mActivities;final int index = activities.indexOf(r);if (index < (activities.size() - 1)) {task.setFrontOfTask();if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {// If the caller asked that this activity (and all above it)// be cleared when the task is reset, don't lose that information,// but propagate it up to the next activity.ActivityRecord next = activities.get(index+1);next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);}}//暂停key的分发事件r.pauseKeyDispatchingLocked();adjustFocusedActivityStack(r, "finishActivity");finishActivityResultsLocked(r, resultCode, resultData);final boolean endTask = index <= 0 && !task.isClearingToReuseTask();final int transit = endTask ? TRANSIT_TASK_CLOSE : TRANSIT_ACTIVITY_CLOSE;if (mResumedActivity == r) {if (DEBUG_VISIBILITY || DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,"Prepare close transition: finishing " + r);if (endTask) {mService.mTaskChangeNotificationController.notifyTaskRemovalStarted(task.taskId);}mWindowManager.prepareAppTransition(transit, false);// Tell window manager to prepare for this one to be removed.r.setVisibility(false);if (mPausingActivity == null) {if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish needs to pause: " + r);if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,"finish() => pause with userLeaving=false");//回调activity的onPause方法startPausingLocked(false, false, null, pauseImmediately);/// M: onBeforeActivitySwitch @{ActivityRecord nextResumedActivity =mStackSupervisor.getFocusedStack().topRunningActivityLocked();if (nextResumedActivity != null) {mService.mAmsExt.onBeforeActivitySwitch(mService.mLastResumedActivity,nextResumedActivity, true, nextResumedActivity.getActivityType());}/// M: onBeforeActivitySwitch @}}if (endTask) {mService.getLockTaskController().clearLockedTask(task);}} else if (!r.isState(PAUSING)) {// If the activity is PAUSING, we will complete the finish once// it is done pausing; else we can just directly finish it here.if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + r);if (r.visible) {prepareActivityHideTransitionAnimation(r, transit);}final int finishMode = (r.visible || r.nowVisible) ? FINISH_AFTER_VISIBLE: FINISH_AFTER_PAUSE;final boolean removedActivity = finishCurrentActivityLocked(r, finishMode, oomAdj,"finishActivityLocked") == null;// The following code is an optimization. When the last non-task overlay activity// is removed from the task, we remove the entire task from the stack. However,// since that is done after the scheduled destroy callback from the activity, that// call to change the visibility of the task overlay activities would be out of// sync with the activitiy visibility being set for this finishing activity above.// In this case, we can set the visibility of all the task overlay activities when// we detect the last one is finishing to keep them in sync.if (task.onlyHasTaskOverlayActivities(true /* excludeFinishing */)) {for (ActivityRecord taskOverlay : task.mActivities) {if (!taskOverlay.mTaskOverlay) {continue;}prepareActivityHideTransitionAnimation(taskOverlay, transit);}}return removedActivity;} else {if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + r);}return false;} finally {mWindowManager.continueSurfaceLayout();}}
十、UIHandler
通过mUiHandler
发送message
,且消息的msg.waht=SHOW_ERROR_MSG
,接下来进入UiHandler
来看看handleMessage
的处理过程。
ActivityManagerService.java
final class UiHandler extends Handler {public void handleMessage(Message msg) {switch (msg.what) {case SHOW_ERROR_MSG: {HashMap<String, Object> data = (HashMap<String, Object>) msg.obj;synchronized (ActivityManagerService.this) {ProcessRecord proc = (ProcessRecord)data.get("app");AppErrorResult res = (AppErrorResult) data.get("result");、boolean isBackground = (UserHandle.getAppId(proc.uid)>= Process.FIRST_APPLICATION_UID&& proc.pid != MY_PID);...if (mShowDialogs && !mSleeping && !mShuttingDown) {//创建提示crash对话框,等待用户选择,5分钟操作等待。Dialog d = new AppErrorDialog(mContext,ActivityManagerService.this, res, proc);d.show();proc.crashDialog = d;} else {//当处于sleep状态,则默认选择退出。if (res != null) {res.set(0);}}}} break;...}
}
在发生Crash
时,默认系统会弹出提示crash
的对话框,并阻塞等待用户选择是“退出”或 “退出并报告”,当用户不做任何选择时5min
超时后,默认选择“退出”,当手机休眠时也默认选择“退出”。到这里也并没有真正结束,在小节2.uncaughtException
中在finnally
语句块还有一个杀进程的动作。
十一 、 killProcess
Process.killProcess(Process.myPid());
System.exit(10);
通过finnally
语句块保证能执行并彻底杀掉Crash
进程。当Crash
进程被杀后,并没有完全结束,还有Binder
死亡通知的流程还没有处理完成
十二、小结
当进程抛出未捕获异常时,则系统会处理该异常并进入Crash
处理流程。
Crash处理流程
其中最为核心的工作图中红色部分AMS.handleAppCrashLocked
的主要功能:
当同一进程1分钟之内连续两次
Crash
,则执行的情况下:
对于非persistent
进程:
-ASS.handleAppCrashLocked,
直接结束该应用所有activity
AMS.removeProcessLocked,
杀死该进程以及同一个进程组下的所有进
-ASS.resumeTopActivitiesLocked
,恢复栈顶第一个非finishing
状态的activity
对于persistent进程,则只执行
ASS.resumeTopActivitiesLocked
,恢复栈顶第一个非finishing
状态的activity
2.否则,当进程没连续频繁crash
ASS.finishTopRunningActivityLocked
,执行结束栈顶正在运行activity
另外,AMS.handleAppCrashLocked
,该方法内部主要调用链,如下:
AMS.handleAppCrashLockedASS.handleAppCrashLockedAS.handleAppCrashLockedAS.finishCurrentActivityLockedAMS.removeProcessLockedProcessRecord.killAMS.handleAppDiedLockedASS.handleAppDiedLockedAMS.cleanUpApplicationRecordLockedAS.handleAppDiedLockedAS.removeHistoryRecordsForAppLockedASS.resumeTopActivitiesLockedAS.resumeTopActivityLockedAS.resumeTopActivityInnerLockedASS.finishTopRunningActivityLockedAS.finishTopRunningActivityLockedAS.finishActivityLocked
至此,本篇已结束。转载网络的文章,小编觉得很优秀,欢迎点击阅读原文,支持原创作者,如有侵权,恳请联系小编删除。同时感谢您的阅读,期待您的关注。
点个在看,方便您使用时快速查找!
深入理解Android Crash 流程相关推荐
- 结合源码深入理解Android Crash处理流程
应用程序crash在开发过程中还是很常见的,本文主要是从源码的角度去跟踪下Android对于crash的处理流程.App crash的全称:Application crash.而Crash又分为:na ...
- 理解Native Crash处理流程
本文是基于Android 7.0源码,来分析Native Crash流程. 转自 http://gityuan.com/2016/06/25/android-native-crash/ 一.Nativ ...
- 深入理解 Android 9.0 Crash 机制(二)
极力推荐Android 开发大总结文章:欢迎收藏 Android 开发技术文章大总结 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容: 九. AppError ...
- 深入理解Android:卷II
<深入理解Android:卷II> 基本信息 作者: 邓凡平 出版社:机械工业出版社 ISBN:9787111389187 上架时间:2012-8-3 出版日期:2012 年8月 开本:1 ...
- Android 7.1.2(Android N) Android系统启动流程
Android 7.1.2(Android N) Android系统启动流程 源码: system/core/rootdir/ init.rc init.zygote64.rc system/core ...
- 8.学习Camera之——Android开机流程
Android系统启动流程 要求:掌握Android系统的启动流程,每个阶段的区别和作用. 一. android系统架构 andorid系统架构从上到下分别有应用层.应用框架层.系统运行时库层.硬件抽 ...
- [深入理解Android卷二 全文-第六章]深入理解ActivityManagerService
由于<深入理解Android 卷一>和<深入理解Android卷二>不再出版,而知识的传播不应该因为纸质媒介的问题而中断,所以我将在CSDN博客中全文转发这两本书的全部内容 第 ...
- android6.0中app crash流程分析
要根据这个流程分析一下如何在应用中截获系统的app crash弹框,然后做到更人性化 基于Android 6.0的源码剖析, 分析Android应用Crash是如何处理的. /frameworks/b ...
- 《深入理解Android:Wi-Fi,NFC和GPS》章节连载[节选]--第二章 深入理解Netd
原文: http://blog.csdn.net/innost/article/details/20400389 本文使用的源码版本为Android5.1 本章主要内容 介绍Netd; 介绍MDNS和 ...
最新文章
- 用stringstream可以用指定字符分割字符串
- 推荐一款好工具:16进制字节搜索工具 C#的效率
- python文件路径操作及pathlib库
- Linux命令之pstree - 以树状图显示进程间的关系
- 如何使用 SQL Server FILESTREAM 存储非结构化数据?这篇文章告诉你!
- ip地址配置 mongodb_MongoDB安全配置详解
- 国内程序员加班严重!听听外国网友怎么说。
- cad显示驱动程序文件已丢失或损坏_win7系统下打开AutoCAD 2014时显示驱动程序文件.hdi丢失如何解决...
- python 连续等于
- windows如何安装pycharm2022版本?pycharm如何安装汉化语言包{www.423zy.com}
- Nsight Compute 使用
- 我大ps可以N倍长腿
- it民工的华丽亦或是失败的转型(一)
- IM 即时通讯系统【源码好优多】
- 相律公式表达式_第六章 相平衡主要公式及其适用条件
- OpenRisc-6-wishbone实验
- java gprs通信教程_S7-1200 GPRS通讯快速入门
- 业务异步写mysql数据库_把重要的业务日志异步批量写入数据库
- 读书笔记:《谁说菜鸟不会数据分析-入门篇》第1-4章
- 殊荣双至,天翼云边缘计算再获两项大奖!
热门文章
- java 引用其他类_java如何调用其他类中的方法?
- 8.3 开始使用truffle-contract
- 新绝代双骄3终极全攻略5
- 任正非揭秘华为鸿蒙,任正非揭秘!华为鸿蒙系统,比安卓、苹果系统快,为物联网而生...
- 【GitHub学生包】2022年12月GitHub学生包最新申请教程 18次认证失败的经验之谈
- 电脑右键新建没有记事本怎么办?
- 计院生活--第一章 卧薪尝胆
- iconfont的使用,阿里矢量图库的引用,配置,改变图标大小和图标颜色
- HTTP与HTTPS是啥?
- Nginx设置访问Web页面时用户名密码验证