深入了解 Android 9.0 Crash 机制(一)

  • 时间:2019-06-11 01:25 作者:ProgramAndroid 来源:ProgramAndroid 阅读:509
  • 扫一扫,手机访问
摘要:极力推荐Android 开发大总结文章:欢迎收藏Android 开发技术文章大总结 本篇文章主要详情 Android 9.0 Crash 机制部分知识点,通过阅读本篇文章,您将收获以下内容:一、Crash 概述二、Crash解决流程三、handleApplicationCrash解决分析四、hand

极力推荐Android 开发大总结文章:欢迎收藏
Android 开发技术文章大总结

本篇文章主要详情 Android 9.0 Crash 机制部分知识点,通过阅读本篇文章,您将收获以下内容:

一、Crash 概述
二、Crash解决流程
三、handleApplicationCrash解决分析
四、handleApplicationCrashInner 解决分析
五、APP Error info分析
六、makeAppCrashingLocked解决分析
七、startAppProblemLocked解决分析
八、stopFreezingAllLocked解决分析

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("\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 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<ProcessRecord>();对于代码mProcessNames.getMap()返回的是mMap,而mMap= new ArrayMap<String, SparseArray<ProcessRecord>>();

知识延伸: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代表的是时间戳)

5.五、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.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.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<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

    @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);    }}
长按识别二维码,领福利

至此,本篇已结束,如有不对的地方,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢!

如有侵权,请联络小编,小编对此深感抱歉,届时小编会删除文章,立即中止侵权行为,请您多多包涵。

  • 全部评论(0)
最新发布的资讯信息
【系统环境|】Fortigate飞塔防火墙如何开启DNS转发/DNS代理(2025-10-14 23:58)
【系统环境|】有了它,再也不用担心电脑弹窗广告和病毒啦!(2025-10-14 23:57)
【系统环境|】如何关闭恼人的电脑弹窗广告?2招搞定(2025-10-14 23:55)
【系统环境|】实用软件推荐:电脑广告弹窗多?用他,都给你屏蔽掉!(2025-10-14 23:55)
【系统环境|】Nginx篇01——基本安装配置和静态页面设置(2025-10-14 23:54)
【系统环境|】Linux端口开放,查看,删除,防火墙(2025-10-14 23:53)
【系统环境|】安全HTTP头部配置: 基于CSP与HSTS的Web安全策略(2025-10-14 23:52)
【系统环境|】老K:做私域过1000万的赛道全部都聚焦在女性身上!(2025-10-14 23:51)
【系统环境|】JavaScript跨域问题: 如何解决跨域访问和资源共享的安全策略(2025-10-14 23:51)
【系统环境|】家庭七级财务防火墙(2025-10-14 23:50)
手机二维码手机访问领取大礼包
返回顶部