理解 Android Crash 处理流

基于Android 6.0 的源码剖析, 分析 Android 应用 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

一、概述

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进程:文章Android系统启动-SystemServer上篇,system_server启动过程中由RuntimeInit.java的commonInit方法设置UncaughtHandler,用于处理未捕获异常;
  • 对于普通应用进程:文章理解Android进程创建流程 ,进程创建过程中,同样会调用RuntimeInit.java的commonInit方法设置UncaughtHandler。

1.1 crash调用链

crash流程的方法调用关系来结尾:

  • AMP.handleApplicationCrash
  • AMS.handleApplicationCrash
  • AMS.findAppProcess
  • AMS.handleApplicationCrashInner
  • AMS.addErrorToDropBox
  • AMS.crashApplication
  • AMS.makeAppCrashingLocked
  • AMS.startAppProblemLocked
  • ProcessRecord.stopFreezingAllLocked
  • ActivityRecord.stopFreezingScreenLocked
  • WMS.stopFreezingScreenLocked
  • WMS.stopFreezingDisplayLocked
  • AMS.handleAppCrashLocked
  • mUiHandler.sendMessage(SHOW_ERROR_MSG)
  • Process.killProcess(Process.myPid());
  • System.exit(10);

接下来说说这个过程。

二、Crash处理流程

那么接下来以commonInit()方法为起点来展开说明。

1. RuntimeInit.commonInit

  • public class RuntimeInit {
  • ...
  • private static final void commonInit() {
  • //设置默认的未捕获异常处理器,UncaughtHandler实例化过程【见小节2】
  • Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
  • ...
  • }
  • }

setDefaultUncaughtExceptionHandler()只是将异常处理器handler对象赋给Thread成员变量,即Thread.defaultUncaughtHandler = new UncaughtHandler()。接下来看看UncaughtHandler对象实例化过程。

2. UncaughtHandler

[–>RuntimeInit.java]

  • private static class UncaughtHandler implements Thread.UncaughtExceptionHandler {
  • //覆写接口方法
  • public void uncaughtException(Thread t, Throwable e) {
  • try {
  • //保证crash处理过程不会重入
  • if (mCrashing) return;
  • mCrashing = true;
  • if (mApplicationObject == null) {
  • //system_server进程
  • Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
  • } else {
  • //普通应用进程
  • 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);
  • }
  • //启动crash对话框,等待处理完成 【见小节2.1和3】
  • ActivityManagerNative.getDefault().handleApplicationCrash(
  • mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
  • } catch (Throwable t2) {
  • ...
  • } finally {
  • //确保当前进程彻底杀掉【见小节11】
  • Process.killProcess(Process.myPid());
  • System.exit(10);
  • }
  • }
  • }
  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

当输出完crash信息到logcat里面,这只是crash流程的刚开始阶段,接下来弹出crash对话框,ActivityManagerNative.getDefault()返回的是ActivityManagerProxy(简称AMP),AMP经过binder调用最终交给ActivityManagerService(简称AMS)中相应的方法去处理,故接下来调用的是AMS.handleApplicationCrash()。

注意: mApplicationObject等于null,一定不是普通的app进程. 但是除了system进程, 也有可能是shell进程, 即通过app_process + 命令参数 的方式创建的进程.

2.1 CrashInfo

[-> ApplicationErrorReport.java]

  • public class ApplicationErrorReport implements Parcelable {
  • ...
  • public static class CrashInfo {
  • public CrashInfo(Throwable tr) {
  • StringWriter sw = new StringWriter();
  • PrintWriter pw = new FastPrintWriter(sw, false, 256);
  • tr.printStackTrace(pw); //输出栈trace
  • pw.flush();
  • stackTrace = 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;
  • }
  • }
  • exceptionClassName = rootTr.getClass().getName();
  • if (rootTr.getStackTrace().length > 0) {
  • StackTraceElement trace = rootTr.getStackTrace()[0];
  • throwFileName = trace.getFileName();
  • throwClassName = trace.getClassName();
  • throwMethodName = trace.getMethodName();
  • throwLineNumber = trace.getLineNumber();
  • } else {
  • throwFileName = "unknown";
  • throwClassName = "unknown";
  • throwMethodName = "unknown";
  • throwLineNumber = 0;
  • }
  • }
  • ...
  • }
  • }

将crash信息文件名类名方法名对应行号以及异常信息都封装到CrashInfo对象。

3. handleApplicationCrash

[–>ActivityManagerService.java]

  • public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
  • //获取进程record对象【见小节3.1】
  • ProcessRecord r = findAppProcess(app, "Crash");
  • final String processName = app == null ? "system_server"
  • : (r == null ? "unknown" : r.processName);
  • //【见小节4】
  • handleApplicationCrashInner("crash", r, processName, crashInfo);
  • }

关于进程名(processName):

  1. 当远程IBinder对象为空时,则进程名为system_server
  2. 当远程IBinder对象不为空,且ProcessRecord为空时,则进程名为unknown;
  3. 当远程IBinder对象不为空,且ProcessRecord不为空时,则进程名为ProcessRecord对象中相应进程名。

3.1 findAppProcess

[–>ActivityManagerService.java]

  • private ProcessRecord findAppProcess(IBinder app, String reason) {
  • if (app == null) {
  • return null;
  • }
  • 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>>();

知识延伸:SparseArrayArrayMap是Android专门针对内存优化而设计的取代Java API中的HashMap的数据结构。对于key是int类型则使用SparseArray,可避免自动装箱过程;对于key为其他类型则使用ArrayMapHashMap的查找和插入时间复杂度为O(1)的代价是牺牲大量的内存来实现的,而SparseArrayArrayMap性能略逊于HashMap,但更节省内存。

再回到mMap,这是以进程name为key,再以(uid为key,以ProcessRecord为Value的)结构体作为value。下面看看其get()和put()方法

  • //获取mMap中(name,uid)所对应的ProcessRecord
  • public ProcessRecord get(String name, int uid) {};
  • //将(name,uid, value)添加到mMap
  • public ProcessRecord put(String name, int uid, ProcessRecord value) {};

findAppProcess()根据app(IBinder类型)来查询相应的目标对象ProcessRecord。

有了进程记录对象ProcessRecord和进程名processName,则进入执行Crash处理方法,继续往下看。

4. handleApplicationCrashInner

[–>ActivityManagerService.java]

  • void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
  • ApplicationErrorReport.CrashInfo crashInfo) {
  • //将Crash信息写入到Event log
  • EventLog.writeEvent(EventLogTags.AM_CRASH,...);
  • //将错误信息添加到DropBox
  • addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);
  • //【见小节5】
  • crashApplication(r, crashInfo);
  • }

其中addErrorToDropBox是将crash的信息输出到目录/data/system/dropbox。例如system_server的dropbox文件名为system_server_crash@xxx.txt (xxx代表的是时间戳)

5. crashApplication

[–>ActivityManagerService.java]

  • private void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
  • long timeMillis = System.currentTimeMillis();
  • 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) {
  • // 当存在ActivityController的情况,比如monkey
  • if (mController != null) {
  • try {
  • String name = r != null ? r.processName : null;
  • int pid = r != null ? r.pid : Binder.getCallingPid();
  • int uid = r != null ? r.info.uid : Binder.getCallingUid();
  • //调用monkey的appCrashed
  • if (!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) {
  • r.kill("crash", true);
  • } else {
  • Process.killProcess(pid);
  • killProcessGroup(uid, pid);
  • }
  • }
  • return;
  • }
  • } catch (RemoteException e) {
  • mController = null;
  • Watchdog.getInstance().setActivityController(null);
  • }
  • }
  • //清除远程调用者uid和pid信息,并保存到origId
  • final long origId = Binder.clearCallingIdentity();
  • ...
  • //【见小节6】
  • if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace)) {
  • Binder.restoreCallingIdentity(origId);
  • 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,弹出提示crash的对话框,等待用户选择【见小节10】
  • mUiHandler.sendMessage(msg);
  • //恢复远程调用者uid和pid
  • Binder.restoreCallingIdentity(origId);
  • }
  • //进入阻塞等待,直到用户选择crash对话框"退出"或者"退出并报告"
  • int res = result.get();
  • Intent appErrorIntent = null;
  • synchronized (this) {
  • if (r != null && !r.isolated) {
  • // 将崩溃的进程信息保存到mProcessCrashTimes
  • mProcessCrashTimes.put(r.info.processName, r.uid,
  • SystemClock.uptimeMillis());
  • }
  • if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
  • //创建action="android.intent.action.APP_ERROR",组件为r.errorReportReceiver的Intent
  • appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
  • }
  • }
  • if (appErrorIntent != null) {
  • try {
  • //启动Intent为appErrorIntent的Activity
  • mContext.startActivityAsUser(appErrorIntent, new UserHandle(r.userId));
  • } catch (ActivityNotFoundException e) {
  • Slog.w(TAG, "bug report receiver dissappeared", e);
  • }
  • }
  • }

该方法主要做的两件事:

  • 调用makeAppCrashingLocked,继续处理crash流程;
  • 发送消息SHOW_ERROR_MSG,弹出提示crash的对话框,等待用户选择;

6. makeAppCrashingLocked

[–>ActivityManagerService.java]

  • private boolean makeAppCrashingLocked(ProcessRecord app,
  • String shortMsg, String longMsg, String stackTrace) {
  • 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", shortMsg, longMsg, stackTrace);
  • }

7. startAppProblemLocked

[–>ActivityManagerService.java]

  • void startAppProblemLocked(ProcessRecord app) {
  • app.errorReportReceiver = null;
  • for (int userId : mCurrentProfileIds) {
  • if (app.userId == userId) {
  • //获取当前用户下的crash应用的error receiver【见小节7.1】
  • app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
  • mContext, app.info.packageName, app.info.flags);
  • }
  • }
  • //忽略当前app的广播接收【见小节7.2】
  • skipCurrentReceiverLocked(app);
  • }

该方法主要功能:

  • 获取当前用户下的crash应用的error receiver;
  • 忽略当前app的广播接收;

7.1 getErrorReportReceiver

[-> ApplicationErrorReport.java]

  • 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();
  • String candidate = null;
  • ComponentName result = null;
  • try {
  • //获取该crash应用的安装器的包名
  • candidate = pm.getInstallerPackageName(packageName);
  • } catch (IllegalArgumentException e) {
  • }
  • if (candidate != null) {
  • result = getErrorReportReceiver(pm, packageName, candidate);//【见下文】
  • if (result != null) {
  • //2.当找到该crash应用的安装器,则返回;
  • return result;
  • }
  • }
  • if ((appFlags&ApplicationInfo.FLAG_SYSTEM) != 0) {
  • //该系统属性名为"ro.error.receiver.system.apps"
  • 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]

  • void skipCurrentReceiverLocked(ProcessRecord app) {
  • for (BroadcastQueue queue : mBroadcastQueues) {
  • queue.skipCurrentReceiverLocked(app); //【见小节7.2.1】
  • }
  • }
7.2.1 skipCurrentReceiverLocked

[-> BroadcastQueue.java]

  • 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 && mPendingBroadcast != null && mPendingBroadcast.curApp == app) {
  • r = mPendingBroadcast;
  • }
  • if (r != null) {
  • //结束app进程的广播结束
  • finishReceiverLocked(r, r.resultCode, r.resultData,
  • r.resultExtras, r.resultAbort, false);
  • //广播调度
  • scheduleBroadcastsLocked();
  • }
  • }

8. PR.stopFreezingAllLocked

[-> ProcessRecord.java]

  • public void stopFreezingAllLocked() {
  • int i = activities.size();
  • while (i > 0) {
  • i--;
  • activities.get(i).stopFreezingScreenLocked(true); //【见小节8.1】
  • }
  • }

其中activities类型为ArrayList<ActivityRecord>,停止进程里所有的Activity

8.1. AR.stopFreezingScreenLocked

[-> ActivityRecord.java]

  • public void stopFreezingScreenLocked(boolean force) {
  • if (force || frozenBeforeDestroy) {
  • frozenBeforeDestroy = false;
  • //mWindowManager类型为WMS //【见小节8.1.1】
  • service.mWindowManager.stopAppFreezingScreen(appToken, force);
  • }
  • }

其中appToken是IApplication.Stub类型,即WindowManager的token。

8.1.1 WMS.stopFreezingScreenLocked

[-> WindowManagerService.java]

  • @Override
  • public void stopFreezingScreen() {
  • //权限检查
  • if (!checkCallingPermission(android.Manifest.permission.FREEZE_SCREEN,
  • "stopFreezingScreen()")) {
  • throw new SecurityException("Requires FREEZE_SCREEN permission");
  • }
  • synchronized(mWindowMap) {
  • if (mClientFreezingScreen) {
  • mClientFreezingScreen = false;
  • mLastFinishedFreezeSource = "client";
  • final long origId = Binder.clearCallingIdentity();
  • try {
  • stopFreezingDisplayLocked(); //【见流程8.1.1.1】
  • } finally {
  • Binder.restoreCallingIdentity(origId);
  • }
  • }
  • }
  • }
8.1.1.1 WMS.stopFreezingDisplayLocked

[-> WindowManagerService.java]

  • private 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;
  • //获取默认的DisplayContent
  • final 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;
  • }
  • //加载动画最大时长为10s
  • if (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);
  • }
  • }

该方法主要功能:

  1. 处理屏幕旋转相关逻辑;
  2. 移除冻屏的超时消息;
  3. 屏幕旋转动画的相关操作;
  4. 使能输入事件分发功能;
  5. display冻结时,执行gc操作;
  6. 更新当前的屏幕方向;
  7. 向mH发送configuraion改变的消息。

9.AMS.handleAppCrashLocked

[-> ActivityManagerService.java]
```java
private boolean handleAppCrashLocked(ProcessRecord app, String reason,
String shortMsg, String longMsg, String stackTrace) {
long now = SystemClock.uptimeMillis();

  • Long crashTime;
  • if (!app.isolated) {
  • crashTime = mProcessCrashTimes.get(app.info.processName, app.uid);
  • } else {
  • crashTime = null;
  • }
  • //当同一个进程,连续两次crash的时间间隔小于1分钟时,则认为crash太过于频繁
  • if (crashTime != null && now < crashTime+ProcessList.MIN_CRASH_INTERVAL) {
  • EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
  • app.userId, app.info.processName, app.uid);
  • //【见小节9.1】
  • mStackSupervisor.handleAppCrashLocked(app);
  • if (!app.persistent) {
  • //不再重启非persistent进程,除非用户显式地调用
  • EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.userId, app.uid,
  • app.info.processName);
  • if (!app.isolated) {
  • //将当前app加入到mBadProcesses
  • mBadProcesses.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;
  • //移除进程的所有服务,保证不再重启【见小节9.2】
  • removeProcessLocked(app, false, false, "crash");
  • //恢复最顶部的Activity【见小节9.3】
  • mStackSupervisor.resumeTopActivitiesLocked();
  • return false;
  • }
  • mStackSupervisor.resumeTopActivitiesLocked();
  • } else {
  • //此处reason="force-crash"【见小节9.4】
  • mStackSupervisor.finishTopRunningActivityLocked(app, reason);
  • }
  • //运行在当前进程中的所有服务的crash次数执行加1操作
  • for (int i=app.services.size()-1; i>=0; i--) {
  • ServiceRecord sr = app.services.valueAt(i);
  • sr.crashCount++;
  • }
  • //当桌面应用crash,并且被三方app所取代,那么需要清空桌面应用的偏爱选项。
  • final ArrayList<ActivityRecord> activities = app.activities;
  • if (app == mHomeProcess && activities.size() > 0
  • && (mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
  • for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
  • final ActivityRecord r = activities.get(activityNdx);
  • if (r.isHomeActivity()) {
  • //清空偏爱应用
  • ActivityThread.getPackageManager()
  • .clearPackagePreferredActivities(r.packageName);
  • }
  • }
  • }
  • if (!app.isolated) {
top Created with Sketch.