日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

本篇文章主要介紹 Android 9.0 Crash 機(jī)制部分知識(shí)點(diǎn),通過(guò)閱讀本篇文章,您將收獲以下內(nèi)容:

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

Android 9.0 Crash 機(jī)制調(diào)用鏈

/frameworks/base/core/JAVA/com/android/internal/os/RuntimeInit.java
/frameworks/base/core/java/android/app/ActivityManagerNative.java (含內(nèi)部類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), 對(duì)于Crash可分為Native Crash和 Framework Crash(包含app crash在內(nèi)),對(duì)于Crash相信很多app開(kāi)發(fā)者都會(huì)遇到,那么上層什么時(shí)候會(huì)出現(xiàn)Crash呢,系統(tǒng)又是如何處理Crash的呢。例如,在app大家經(jīng)常使用try...catch語(yǔ)句,那么如果沒(méi)有有效catch exception,就是導(dǎo)致應(yīng)用Crash,發(fā)生沒(méi)有catch exception,系統(tǒng)便會(huì)來(lái)進(jìn)行捕獲,并進(jìn)入Crash流程。如果你是從事Android系統(tǒng)開(kāi)發(fā)或者架構(gòu)相關(guān)工作,或者遇到需要解系統(tǒng)性的疑難雜癥,那么很有必要了解系統(tǒng)Crash處理流程,知其然還需知其所以然;如果你僅僅是App初級(jí)開(kāi)發(fā),可能本文并非很適合閱讀,整個(gè)系統(tǒng)流程錯(cuò)綜復(fù)雜。

在Android系統(tǒng)啟動(dòng)系列文章,已講述過(guò)上層應(yīng)用都是由Zygote fork孵化而來(lái),分為system_server系統(tǒng)進(jìn)程和各種應(yīng)用進(jìn)程,在這些進(jìn)程創(chuàng)建之初會(huì)設(shè)置未捕獲異常的處理器,當(dāng)系統(tǒng)拋出未捕獲的異常時(shí),最終都交給異常處理器。

  • 對(duì)于system_server進(jìn)程:system_server啟動(dòng)過(guò)程中由RuntimeInit.java的commonInit方法設(shè)置UncaughtHandler,用于處理未捕獲異常;
  • 對(duì)于普通應(yīng)用進(jìn)程:進(jìn)程創(chuàng)建過(guò)程中,同樣會(huì)調(diào)用RuntimeInit.java的commonInit方法設(shè)置UncaughtHandler。

1.1 crash調(diào)用鏈

crash流程的方法調(diào)用關(guān)系如下:

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方法會(huì)調(diào)用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!");
 }

那么接下來(lái)以commonInit()方法為起點(diǎn)來(lái)展開(kāi)說(shuō)明。

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對(duì)象賦給Thread成員變量,
 Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));
 ... ...

 }

接下來(lái)我們看看LoggingHandler的實(shí)現(xiàn)。LoggingHandler實(shí)現(xiàn) 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處理過(guò)程不會(huì)重入
 if (mCrashing) return;
 //mApplicationObject等于null,一定不是普通的app進(jìn)程. 
 //但是除了system進(jìn)程, 也有可能是shell進(jìn)程, 
 //即通過(guò)app_process + 命令參數(shù) 的方式創(chuàng)建的進(jìn)程.
 if (mApplicationObject == null && (Process.SYSTEM_UID == Process.myUid())) { 
 //系統(tǒng) 進(jìn)程Crash打印的Log 信息
 /**
 發(fā)生 系統(tǒng)Crash 時(shí)候可以搜索 關(guān)鍵字 FATAL EXCEPTION IN SYSTEM PROCESS
 **/
 Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
 } else {
 /**
 發(fā)生 APP Crash 時(shí)候可以搜索 關(guān)鍵字 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.當(dāng)System進(jìn)程Crash的信息:

開(kāi)頭 FATAL EXCEPTION IN SYSTEM PROCESS [線程名],接著輸出Crash時(shí)的調(diào)用棧信息;

  • 2.當(dāng)app進(jìn)程Crash時(shí)的信息:

開(kāi)頭 FATAL EXCEPTION: [線程名],緊接著 Process: [進(jìn)程名], PID: [進(jìn)程id];最后輸出發(fā)生Crash時(shí)的調(diào)用棧信息。

看到這里,你就會(huì)發(fā)現(xiàn)要從log中搜索Crash信息,只需要搜索關(guān)鍵詞 FATAL EXCEPTION,即可查看出是那種異常;如果需要進(jìn)一步篩選只搜索系統(tǒng)crash信息,則可以搜索的關(guān)鍵詞可以有多樣,比如 FATAL EXCEPTION IN SYSTEM PROCESS

當(dāng)輸出完Crash信息到logcat里面,這只是Crash流程的剛開(kāi)始階段,接下來(lái)彈出Crash對(duì)話框,ActivityManagerNative.getDefault()返回的是ActivityManagerProxy(簡(jiǎn)稱AMP),AMP經(jīng)過(guò)binder調(diào)用最終交給ActivityManagerService(簡(jiǎn)稱AMS)中相應(yīng)的方法去處理,然后調(diào)用的是AMS.handleApplicationCrash()。

分析完LoggingHandler后,我們繼續(xù)看setDefaultUncaughtExceptionHandler(),它只是將異常處理器handler對(duì)象賦給Thread成員變量,即Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));。接下來(lái)看看KillApplicationHandler對(duì)象實(shí)例化過(guò)程。

2. KillApplicationHandler

RuntimeInit.java

KillApplicationHandler 實(shí)現(xiàn) Thread.UncaughtExceptionHandler方法,主要處理由于未捕獲的異常Crash導(dǎo)致APP 崩潰,運(yùn)行在Main Thread的Framework 代碼會(huì)捕獲這些異常。

KillApplicationHandler 方法需要傳遞一個(gè)LoggingHandler的參數(shù),
既 LoggingHandler loggingHandler = new LoggingHandler();,LoggingHandler在上文已經(jīng)分析過(guò),接下來(lái)我們看看KillApplicationHandler方法.

KillApplicationHandler方法如下:

 private static class KillApplicationHandler implements Thread.UncaughtExceptionHandler {
 private final LoggingHandler mLoggingHandler;
 public KillApplicationHandler(LoggingHandler loggingHandler) {
 // 構(gòu)造方法,初始化 loggingHandler 
 this.mLoggingHandler = Objects.requireNonNull(loggingHandler);
 }

 @Override
 public void uncaughtException(Thread t, Throwable e) {
 try {
 ensureLogging(t, e);

 // 保證crash處理過(guò)程不會(huì)重入
 if (mCrashing) return;
 mCrashing = true;
 ... ...
 //啟動(dòng)crash對(duì)話框,等待處理完成 【見(jiàn)小節(jié)2.1和3】
 ActivityManager.getService().handleApplicationCrash(
 mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
 } catch (Throwable t2) {
 ... ... 
 } finally {
 //確保當(dāng)前進(jìn)程徹底殺掉【見(jiàn)小節(jié)11】
 Process.killProcess(Process.myPid());
 System.exit(10);
 }
 }
 ... ...
}

接下來(lái)我們看看啟動(dòng)Crash彈窗的處理。new ApplicationErrorReport.ParcelableCrashInfo(e)方法。

2.1 ApplicationErrorReport.ParcelableCrashInfo

ApplicationErrorReport 主要用來(lái)描述 APP Error信息。
APP ERROR 信息分類如下:

  • TYPE_CRASH: APP Crash 信息
  • TYPE_ANR: APP ANR 信息
  • TYPE_BATTERY: Battery 使用信息
  • TYPE_RUNNING_SERVICE: 正在運(yùn)行的Service 相關(guān)信息
// 主要處理 APP Error 信息public class ApplicationErrorReport implements Parcelable { ... ... public static class ParcelableCrashInfo extends CrashInfo implements Parcelable { //創(chuàng)建 CrashInfo 實(shí)例,初始化異常信息 public ParcelableCrashInfo(Throwable tr) { super(tr); } ... ...  public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
 @Override
 public ParcelableCrashInfo createFromParcel(Parcel in) {
 return new ParcelableCrashInfo(in);
 }

 @Override
 public ParcelableCrashInfo[] newArray(int size) {
 return new ParcelableCrashInfo[size];
 }
 };
 }
 ... ...
}

ParcelableCrashInfo 繼承 CrashInfo,接下來(lái)我們看看 CrashInfo的實(shí)現(xiàn)。

CrashInfo

**CrashInfo ** 主要是將Crash信息文件名,類名,方法名,對(duì)應(yīng)行號(hào)以及異常信息都封裝到CrashInfo對(duì)象。

 // 描述 Crash 信息
 public static class CrashInfo {

 ... ...
 public CrashInfo() {
 }

 //CrashInfo 初始化實(shí)例 
 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 行號(hào)
 throwFileName = trace.getFileName();
 throwClassName = trace.getClassName();
 throwMethodName = trace.getMethodName();
 throwLineNumber = trace.getLineNumber();
 } else {
 throwFileName = "unknown";
 ... ... 
 }

 exceptionMessage = sanitizeString(exceptionMessage);
 }

三、handleApplicationCrash處理分析

handleApplicationCrash 會(huì)通過(guò) JNI接口調(diào)用AMS中的方法。

 //發(fā)送 Crash 彈窗handler,直到Dialog dismiss
 ActivityManager.getService().handleApplicationCrash(
 mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));

ActivityManagerService.java
handleApplicationCrash 通過(guò)JNI 回調(diào)用 AMS中的handleApplicationCrash方法,進(jìn)而調(diào)用AMS 中的內(nèi)部方法handleApplicationCrashInner。
handleApplicationCrash

  • 1.當(dāng)遠(yuǎn)程IBinder對(duì)象為空Null時(shí),則進(jìn)程名為system_server;
  • 2.當(dāng)遠(yuǎn)程IBinder對(duì)象不為空,且ProcessRecord為空時(shí),則進(jìn)程名為unknown;
  • 3.當(dāng)遠(yuǎn)程IBinder對(duì)象不為空,且ProcessRecord不為空時(shí),則進(jìn)程名為ProcessRecord對(duì)象中相應(yīng)進(jìn)程名。
 // 當(dāng)app Crash 時(shí)候,會(huì)調(diào)用此方法。
 //調(diào)用結(jié)束后 ,app 進(jìn)程就會(huì)推出
 public void handleApplicationCrash(IBinder app,
 ApplicationErrorReport.ParcelableCrashInfo crashInfo) {
 // findAppProcess 詳見(jiàn) 3.1 分析
 ProcessRecord r = findAppProcess(app, "Crash");
 // system_server 進(jìn)程 為Null 
 final String processName = app == null ? "system_server"
 : (r == null ? "unknown" : r.processName);
 //handleApplicationCrashInner 詳見(jiàn) 4 分析
 handleApplicationCrashInner("crash", r, processName, crashInfo);
 }

handleApplicationCrashInner主要是調(diào)用 AppErrors類中的crashApplication 方法處理。

 void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
 ApplicationErrorReport.CrashInfo crashInfo) {
 ... ... 
 //調(diào)用APP Error 類方法中的 crashApplication
 mAppErrors.crashApplication(r, crashInfo);
 }

3.1 findAppProcess

ActivityManagerService.java
findAppProcess主要是通過(guò)for循環(huán)遍歷查找出IBinder對(duì)應(yīng)的Process.

 private ProcessRecord findAppProcess(IBinder app, String reason) { ... ... synchronized (this) { final int NP = mProcessNames.getMap().size(); for (int ip=0; ip apps = mProcessNames.getMap().valueAt(ip); final int NA = apps.size(); for (int ia=0; ia ProcessRecord p = apps.valueAt(ia);
 //當(dāng)找到目標(biāo)進(jìn)程則返回
 if (p.thread != null && p.thread.asBinder() == app) {
 return p;
 }
 }
 }
 //如果代碼執(zhí)行到這里,表明無(wú)法找到應(yīng)用所在的進(jìn)程
 return null;
 }
 }

其中 mProcessNames = new ProcessMap();對(duì)于代碼mProcessNames.getMap()返回的是mMap,而mMap= new ArrayMap>();

知識(shí)延伸:SparseArray和ArrayMap是Android專門(mén)針對(duì)內(nèi)存優(yōu)化而設(shè)計(jì)的取代Java API中的HashMap的數(shù)據(jù)結(jié)構(gòu)。

對(duì)于key是int類型則使用SparseArray,可避免自動(dòng)裝箱過(guò)程;
對(duì)于key為其他類型則使用ArrayMap。
HashMap的查找和插入時(shí)間復(fù)雜度為O(1)的代價(jià)是犧牲大量的內(nèi)存來(lái)實(shí)現(xiàn)的,而SparseArray和ArrayMap性能略遜于HashMap,但更節(jié)省內(nèi)存。

再回到mMap,這是以進(jìn)程name為key,再以(uid為key,以ProcessRecord為Value的)結(jié)構(gòu)體作為value。下面看看其get()和put()方法

 public E get(String name, int uid) { SparseArray uids = mMap.get(name); if (uids == null) return null; return uids.get(uid); }  public E put(String name, int uid, E value) { SparseArray uids = mMap.get(name); if (uids == null) { uids = new SparseArray(2);
 mMap.put(name, uids);
 }
 uids.put(uid, value);
 return value;
 }
 

findAppProcess()根據(jù)app(IBinder類型)來(lái)查詢相應(yīng)的目標(biāo)對(duì)象ProcessRecord。

有了進(jìn)程記錄對(duì)象ProcessRecord和進(jìn)程名processName,則進(jìn)入執(zhí)行Crash處理方法 AppErrors.java,繼續(xù)往下看。

四、handleApplicationCrashInner 處理分析

ActivityManagerService.java

 void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
 ApplicationErrorReport.CrashInfo crashInfo) {
 ... ...
 //將錯(cuò)誤信息追加到DropBox
 addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);
 //【見(jiàn)小節(jié)5】
 mAppErrors.crashApplication(r, crashInfo);
 }

其中addErrorToDropBox是將Crash的信息輸出到目錄/data/system/dropbox。例如system_server的dropbox文件名為[email protected] (xxx代表的是時(shí)間戳)

五、APP Error info分析

AppErrors.java
AppErrors 主要是 控制APP Crash的場(chǎng)景條件。

 void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
 ... ...
 try {
 // 調(diào)用內(nèi)部 crashApplicationInner方法
 crashApplicationInner(r, crashInfo, callingPid, callingUid);
 } finally {
 Binder.restoreCallingIdentity(origId);
 }
 }

crashApplicationInner內(nèi)部方法

 void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,
 int callingPid, int callingUid) {
 ... ... 
 AppErrorResult result = new AppErrorResult();
 TaskRecord task;
 synchronized (mService) {
 // 如果是通過(guò)IActivityController 實(shí)例導(dǎo)致的Crash ,則不顯示彈窗
 // 詳見(jiàn)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;
 // 無(wú)法勢(shì)必的進(jìn)程 也不顯示Crash 彈窗【見(jiàn)小節(jié)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;
 //發(fā)送消息SHOW_ERROR_MSG,彈出提示crash的對(duì)話框,等待用戶選擇【見(jiàn)小節(jié)10】
 mService.mUiHandler.sendMessage(msg);
 }
 //進(jìn)入阻塞等待,直到用戶選擇crash對(duì)話框"退出"或者"退出并報(bào)告"
 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,通過(guò)IActivityController 實(shí)例導(dǎo)致的Crash ,則不顯示彈窗.
AppError.java

 private boolean handleAppCrashInActivityController(ProcessRecord r,
 ApplicationErrorReport.CrashInfo crashInfo,
 String shortMsg, String longMsg,
 String stackTrace, long timeMillis,
 int callingPid, int callingUid) {
 ... ... 
 // 當(dāng)存在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;
 //調(diào)用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) {
 //調(diào)用`makeAppCrashingLocked`,繼續(xù)處理crash流程
 // 詳見(jiàn) 小結(jié) 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;
 }

該方法主要做的兩件事:

  • 調(diào)用makeAppCrashingLocked,繼續(xù)處理Crash流程;
  • 發(fā)送消息SHOW_ERROR_MSG,彈出提示Crash的對(duì)話框,等待用戶選擇;
    接下來(lái)我們看makeAppCrashingLocked實(shí)現(xiàn)。

六、makeAppCrashingLocked處理分析

AppError.java

 private boolean makeAppCrashingLocked(ProcessRecord app,
 String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
 app.crashing = true;
 //封裝crash信息到crashingReport對(duì)象
 app.crashingReport = generateProcessError(app,
 ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
 //【見(jiàn)小節(jié)7】
 startAppProblemLocked(app);
 //停止屏幕凍結(jié)【見(jiàn)小節(jié)8】
 app.stopFreezingAllLocked();
 //【見(jiàn)小節(jié)9】
 return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace,
 data);
 }

七、startAppProblemLocked處理分析

AppError.java
startAppProblemLocked 該方法主要功能:

  • 獲取當(dāng)前用戶下的crash應(yīng)用的error receiver;
  • 忽略當(dāng)前App的廣播接收;
 void startAppProblemLocked(ProcessRecord app) {
 // 如果不是當(dāng)前user正在運(yùn)行 app,這置為空
 app.errorReportReceiver = null;

 for (int userId : mService.mUserController.getCurrentProfileIds()) {
 if (app.userId == userId) {
 //獲取當(dāng)前用戶下的crash應(yīng)用的error receiver【見(jiàn)小節(jié)7.1】
 app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
 mContext, app.info.packageName, app.info.flags);
 }
 }
 //忽略當(dāng)前app的廣播接收【見(jiàn)小節(jié)7.2】
 mService.skipCurrentReceiverLocked(app);
 }

7.1 getErrorReportReceiver

ApplicationErrorReport.java
獲取當(dāng)前用戶下的Crash應(yīng)用的error receiver

 public static ComponentName getErrorReportReceiver(Context context,
 String packageName, int appFlags) {
 //檢查Settings中的"send_action_app_error"是否使能錯(cuò)誤報(bào)告的功能
 int enabled = Settings.Global.getInt(context.getContentResolver(),
 Settings.Global.SEND_ACTION_APP_ERROR, 0);
 if (enabled == 0) {
 //1.當(dāng)未使能時(shí),則直接返回
 return null;
 }

 PackageManager pm = context.getPackageManager();

 // look for receiver in the installer package
 String candidate = null;
 ComponentName result = null;

 try {
 //獲取該crash應(yīng)用的安裝器的包名
 candidate = pm.getInstallerPackageName(packageName);
 } catch (IllegalArgumentException e) {
 // the package could already removed
 }

 if (candidate != null) {
 result = getErrorReportReceiver(pm, packageName, candidate);
 if (result != null) {
 //2.當(dāng)找到該crash應(yīng)用的安裝器,則返回;
 return result;
 }
 }

 //該系統(tǒng)屬性名為"ro.error.receiver.system.apps"
 if ((appFlags&ApplicationInfo.FLAG_SYSTEM) != 0) {

 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
 // 通過(guò)上下文對(duì)象傳參,調(diào)用類內(nèi)部方法
 result = getErrorReportReceiver(pm, packageName, candidate);
 if (result != null) {
 //3.當(dāng)crash應(yīng)用是系統(tǒng)應(yīng)用時(shí),且系統(tǒng)屬性指定error receiver時(shí),則返回;
 return result;
 }
 }

 //該默認(rèn)屬性名為"ro.error.receiver.default"
 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
 //4.當(dāng)默認(rèn)屬性值指定error receiver時(shí),則返回;
 return getErrorReportReceiver(pm, packageName, candidate);
 }

getErrorReportReceiver:這是同名不同輸入?yún)?shù)的另一個(gè)方法:

 static ComponentName getErrorReportReceiver(PackageManager pm, String errorPackage,
 String receiverPackage) {
 if (receiverPackage == null || receiverPackage.length() == 0) {
 return null;
 }

 //當(dāng)安裝應(yīng)用程序的安裝器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;
 }
 //創(chuàng)建包名為receiverPackage的組件
 return new ComponentName(receiverPackage, info.activityInfo.name);
 }

7.2 skipCurrentReceiverLocked

ActivityManagerService.java
忽略當(dāng)前app的廣播接收

 void skipCurrentReceiverLocked(ProcessRecord app) {
 for (BroadcastQueue queue : mBroadcastQueues) {
 // 會(huì)調(diào)用BroadcastQueue 中的方法【見(jiàn)小節(jié)7.2.1】
 queue.skipCurrentReceiverLocked(app);
 }
 }

7.2.1 skipCurrentReceiverLocked

BroadcastQueue.java skipCurrentReceiverLocked忽略當(dāng)前app的廣播接收.

 public void skipCurrentReceiverLocked(ProcessRecord app) {
 BroadcastRecord r = null;
 //查看app進(jìn)程中的廣播
 if (mOrderedBroadcasts.size() > 0) {
 BroadcastRecord br = mOrderedBroadcasts.get(0);
 // 判斷是否一致
 if (br.curApp == app) {
 r = br;
 }
 }
 ... ...
 if (r != null) {
 // 見(jiàn)7.2.2
 skipReceiverLocked(r);
 }
 }

7.2.2 skipReceiverLocked

BroadcastQueue.java

 private void skipReceiverLocked(BroadcastRecord r) {
 logBroadcastReceiverDiscardLocked(r);
 //結(jié)束app進(jìn)程的廣播結(jié)束
 finishReceiverLocked(r, r.resultCode, r.resultData,
 r.resultExtras, r.resultAbort, false);
 //執(zhí)行廣播調(diào)度
 scheduleBroadcastsLocked();
 }

八、stopFreezingAllLocked處理分析

AppError.java中的 makeAppCrashingLocked方法(第6步),會(huì)調(diào)用stopFreezingAllLocked 方法

ProcessRecord.java

 public void stopFreezingAllLocked() {
 int i = activities.size();
 while (i > 0) {
 i--;
 // 停止進(jìn)程里所有的`Activity`. 詳見(jiàn)8.1 
 activities.get(i).stopFreezingScreenLocked(true);
 }
 }

其中activities類型為ArrayList,停止進(jìn)程里所有的Activity.

8.1 AR.stopFreezingScreenLocked

ActivityRecord.java,stopFreezingScreenLocked停止進(jìn)程里所有的Activity.

 public void stopFreezingScreenLocked(boolean force) {
 if (force || frozenBeforeDestroy) {
 frozenBeforeDestroy = false;
 // mWindowContainerController 見(jiàn)【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 {
 // 詳見(jiàn) 8.1.1.2
 stopFreezingDisplayLocked();
 } finally {
 Binder.restoreCallingIdentity(origId);
 }
 }
 }
 }

8.1.1.2 stopFreezingDisplayLocked();

WindowManagerService.java
該方法主要功能:

處理屏幕旋轉(zhuǎn)相關(guān)邏輯;
移除凍屏的超時(shí)消息;
屏幕旋轉(zhuǎn)動(dòng)畫(huà)的相關(guān)操作;
使能輸入事件分發(fā)功能;
display凍結(jié)時(shí),執(zhí)行g(shù)c操作;
更新當(dāng)前的屏幕方向;
向mH發(fā)送configuraion改變的消息

rivate void stopFreezingDisplayLocked() {
 if (!mDisplayFrozen) {
 return; //顯示沒(méi)有凍結(jié),則直接返回
 }

 //往往跟屏幕旋轉(zhuǎn)相關(guān)
 ...

 mDisplayFrozen = false;
 //從上次凍屏到現(xiàn)在的總時(shí)長(zhǎng)
 mLastDisplayFreezeDuration = (int)(SystemClock.elapsedRealtime() - mDisplayFreezeTime);

 //移除凍屏的超時(shí)消息
 mH.removeMessages(H.APP_FREEZE_TIMEOUT);
 mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);

 boolean updateRotation = false;
 //獲取默認(rèn)的DisplayContent
 final DisplayContent displayContent = getDefaultDisplayContentLocked();
 final int displayId = displayContent.getDisplayId();
 ScreenRotationAnimation screenRotationAnimation =
 mAnimator.getScreenRotationAnimationLocked(displayId);

 //屏幕旋轉(zhuǎn)動(dòng)畫(huà)的相關(guān)操作
 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;
 }
 //加載動(dòng)畫(huà)最大時(shí)長(zhǎng)為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;
 }
 //經(jīng)過(guò)層層調(diào)用到InputManagerService服務(wù),IMS服務(wù)使能輸入事件分發(fā)功能
 mInputMonitor.thawInputDispatchingLw();

 boolean configChanged;
 //當(dāng)display被凍結(jié)時(shí)不再計(jì)算屏幕方向,以避免不連續(xù)的狀態(tài)。
 configChanged = updateOrientationFromAppTokensLocked(false);

 //display凍結(jié)時(shí),執(zhí)行g(shù)c操作
 mH.removeMessages(H.FORCE_GC);
 mH.sendEmptyMessageDelayed(H.FORCE_GC, 2000);

 //mScreenFrozenLock的類型為PowerManager.WakeLock,即釋放屏幕凍結(jié)的鎖
 mScreenFrozenLock.release();

 if (updateRotation) {
 //更新當(dāng)前的屏幕方向
 configChanged |= updateRotationUncheckedLocked(false);
 }

 if (configChanged) {
 //向mH發(fā)送configuraion改變的消息
 mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
 }
}

分享到:
標(biāo)簽:Android
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定