0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Android 9.0 Crash机制调用链

哆啦安全 来源:哆啦安全 2023-05-09 11:43 次阅读

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 CrashFramework 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.javacommonInit方法设置UncaughtHandler,用于处理未捕获异常;

  • 对于普通应用进程:进程创建过程中,同样会调用RuntimeInit.javacommonInit方法设置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处理流程

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不能 替换 setUncaughtExceptionPreHandler
        Thread.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;

        @Override
        public 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("
");
                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 ThreadFramework代码会捕获这些异常。

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);
        }

        @Override
        public 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>() {
                    @Override
                    public ParcelableCrashInfo createFromParcel(Parcel in) {
                        return new ParcelableCrashInfo(in);
                    }

                    @Override
                    public 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);
            //输出栈trace
            tr.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  dismiss
                ActivityManager.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 类方法中的 crashApplication
        mAppErrors.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();对于代码mProcessNames.getMap()返回的是mMap,而mMap= new ArrayMap>();

知识延伸:SparseArrayArrayMapAndroid专门针对内存优化而设计的取代Java API中的HashMap的数据结构。

对于keyint类型则使用SparseArray,可避免自动装箱过程;
对于key为其他类型则使用ArrayMap
HashMap的查找和插入时间复杂度为O(1)的代价是牺牲大量的内存来实现的,而SparseArrayArrayMap性能略逊于HashMap,但更节省内存

再回到mMap,这是以进程namekey,再以(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) {
         ... ...
        //将错误信息追加到DropBox
        addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);
        //【见小节5】
        mAppErrors.crashApplication(r, crashInfo);
    }

其中addErrorToDropBox是将Crash的信息输出到目录/data/system/dropbox。例如system_serverdropbox文件名为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的情况,比如monkey
        try {
            String name = r != null ? r.processName : null;
            int pid = r != null ? r.pid : callingPid;
            int uid = r != null ? r.info.uid : callingUid;
           //调用monkey的 appCrashed
            if (!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 package
        String 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.javaskipCurrentReceiverLocked忽略当前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.2
            skipReceiverLocked(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,停止进程里所有的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

    @Override
    public void stopFreezingScreen() {
         ... ...
        synchronized(mWindowMap) {
            if (mClientFreezingScreen) {
                mClientFreezingScreen = false;
                mLastFinishedFreezeSource = "client";
                final long origId = Binder.clearCallingIdentity();
                try {
           // 详见 8.1.1.2
                    stopFreezingDisplayLocked();
                } 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;
    //获取默认的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);
    }
}

九、 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 所有的Service
            ServiceRecord sr = app.services.valueAt(i);
            // Service 一会自动起来 重置count 为1,否则+1
            if (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加入到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;
                //移除非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 */);
                    //结束当前activity
                    finishCurrentActivityLocked(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进程设置成可重启flags
            if (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,这是以pidkey,记录着所有的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 app
    TaskRecord 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.1
                final 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.2
        finishActivityLocked(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处理流程。

b593a1b4-ee0a-11ed-90ce-dac502259ad0.jpg

Crash处理流程

其中最为核心的工作图中红色部分AMS.handleAppCrashLocked的主要功能:

  1. 当同一进程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.handleAppCrashLocked
   ASS.handleAppCrashLocked
       AS.handleAppCrashLocked
           AS.finishCurrentActivityLocked
   AMS.removeProcessLocked
       ProcessRecord.kill
       AMS.handleAppDiedLocked
           ASS.handleAppDiedLocked
               AMS.cleanUpApplicationRecordLocked
               AS.handleAppDiedLocked
                   AS.removeHistoryRecordsForAppLocked

   ASS.resumeTopActivitiesLocked
       AS.resumeTopActivityLocked
           AS.resumeTopActivityInnerLocked
   ASS.finishTopRunningActivityLocked
       AS.finishTopRunningActivityLocked
           AS.finishActivityLocked

审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Android
    +关注

    关注

    12

    文章

    3851

    浏览量

    125660
  • 机制
    +关注

    关注

    0

    文章

    24

    浏览量

    9721
  • kill
    +关注

    关注

    0

    文章

    9

    浏览量

    2062

原文标题:十二、小结

文章出处:【微信号:哆啦安全,微信公众号:哆啦安全】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Raspberry Pi 3和3 b +上的Android Pie 9.0

    Raspberry Pi 3和3 b +上的Android Pie 9.0在Raspberry Pi 3上安装Android Oreo 8.1之后,可以在raspberry pi 3上安装和运行
    发表于 09-29 14:28

    怎样去搭建android 9.0的编译环境呢

    飞凌有没有android 9.0的开发板?想先搭建一下android 9.0的编译环境,还能用虚拟机吗,电脑的配置要求多少
    发表于 01-12 06:47

    RK3399 Android 9.0系统永不休眠该怎样去设置呢

    RK3399 Android 9.0系统永不休眠该怎样去设置呢?怎样去更改RK3399 Android 9.0系统的语言呢?
    发表于 03-07 08:55

    如何解决RK3399/RK3328 Android9.0系统点击恢复设置应用崩溃的问题

    是什么原因导致RK3399/RK3328Android9.0系统点击恢复设置应用崩溃的呢?如何解决RK3399/RK3328 Android9.0系统点击恢复设置应用崩溃的问题?
    发表于 03-09 06:09

    RK3288 Android 9.0 eDP界面显示异常怎么解决呢

    RK3288 Android 9.0 eDP界面显示异常是怎么回事?RK3288 Android 9.0 eDP界面显示异常怎么解决呢?
    发表于 03-09 07:25

    深入剖析Android消息机制

    深入剖析Android消息机制
    发表于 01-22 21:11 11次下载

    谷歌将推出Android 9.0,加入生物识别

    谷歌将会在即将推出的Android 9.0版本系统当中加入更好的生物识别API,为开发者提供更安全和方便的生物验证机制
    发表于 06-25 17:55 1278次阅读

    相隔一年,Android 9.0终要发布

    几乎是在明示,Android P将在8月20日发布,安卓9.0终于要修成正果了。巧合的是,安卓8.0去年也是8月20日那天发布的。
    发表于 08-07 11:34 708次阅读
    相隔一年,<b class='flag-5'>Android</b> <b class='flag-5'>9.0</b>终要发布

    华为EMUI 9.0是国内首个适配Android 9.0系统的深度定制系统

    国内首个基于Android 9.0版本深度定制的智能手机系统——华为EMUI 9.0正式在上海发布。华为消费者BG软件工程部总裁王成录为到场媒体和观众讲解EMUI 9.0的新功能和黑科
    发表于 09-09 10:36 9926次阅读

    OPPO新机搭载Android9.0,跑分曝光

    从跑分看,型号为PBDM00的新机有望成OPPO首款搭载Android9.0操作系统的手机。
    的头像 发表于 09-12 11:08 7060次阅读

    Android9.0有哪些亮点

    8月7日,谷歌正式发布了Android 9.0正式版,其代号P的含义也终于真相大白,谷歌将其命名为Pie(馅饼)。首批支持升级的机型仅为自家的Pixel系列,而其他合作厂商的机型会在今年秋天获得更新推送。
    的头像 发表于 11-27 10:58 2608次阅读

    谷歌Pixel系列机型获Android9.0正式版更新推送

    在历经5个Android P Beta版本更新后,谷歌于今日正式推送Android 9.0正式版,定名为Android Pie,谷歌Pixel系列机型将率先获得此更新。
    的头像 发表于 11-27 10:38 3247次阅读

    Core 3399Pro JD4 Android 9.0 SDK源码

    电子发烧友网站提供《Core 3399Pro JD4 Android 9.0 SDK源码.txt》资料免费下载
    发表于 09-02 11:04 1次下载
    Core 3399Pro JD4 <b class='flag-5'>Android</b> <b class='flag-5'>9.0</b> SDK源码

    Core 3399Pro JD4 Android 9.0固件资料

    电子发烧友网站提供《Core 3399Pro JD4 Android 9.0固件资料.txt》资料免费下载
    发表于 09-02 10:53 0次下载
    Core 3399Pro JD4 <b class='flag-5'>Android</b> <b class='flag-5'>9.0</b>固件资料

    AIO 3399ProC固件Android9.0

    电子发烧友网站提供《AIO 3399ProC固件Android9.0.txt》资料免费下载
    发表于 09-21 09:58 11次下载
    AIO 3399ProC固件<b class='flag-5'>Android9.0</b>