天外飞仙-betway官网betway官网手机-betway官网体育-betway必威app下载

阅览五分钟,每日十点,和您一同终身学习,这儿是程序员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.java的commonInit办法设置UncaughtHandler,用于处理未捕获反常;
  • 关于一般运用进程:进程创立进程中,同样会调用RuntimeInit.java的commonInit办法设置UncaughtHandler。

1.1 crash调用链

crash流程的办法调用联系如下:

AMP.handleApplicationCrash
AMS.handleApplicationCrash
AMS.findAppProcess
AMS.handleApplicationCras标签11hInner
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 voi天外飞仙-betway官网betway官网手机-betway官网体育-betway必威app下载d commonInit() {

/*
* set handlers; these apply to all threads in the VM. Apps can replace
* the default handler, but not the pre handler.
*/
LoggingHandler loggingHandler = ne天外飞仙-betway官网betway官网手机-betway官网体育-betway必威app下载w 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对话框,A标签1ctivityManagerNative.getDefault()回来的是ActivityManagerProxy(简称AMP),AMP通过binder调用终究交给ActivityManagerService(简称AMS)中相应的办法去处理,然后调用的是AMS.handleApplicationCrash()。

剖析完LoggingHandler后,咱们持续看setDefaultUncaughtExceptionHandler(),它仅仅将反常处理器handler方针赋给Thread成员变量,即Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));。接下来看看KillApplicationHandler方针实例化进程。

2. KillApplicationHandler

RuntimeInit.java

KillApplicationHandler 完结 Thread.UncaughtExceptionHandler办法,首要处理因为未捕获的反常Crash导致APP 溃散,运转在Main Thread的Framework 代码会捕获这些反常。

KillApplicationHandler 办法需求传递一个LoggingHandler的参数,
既 LoggingHandler loggingHandler = new LoggingHandler();,L标签11oggingHandler在上文现已剖析过,接下来咱们看看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 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,接下来咱们看看 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);
//输出栈trac标签14e
tr.printStackTrace(pw);
pw.flush();
stackTrace = sanitizeString(sw.toString());
except标签14ionMessage = 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.get天外飞仙-betway官网betway官网手机-betway官网体育-betway必威app下载FileName();
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, pr天外飞仙-betway官网betway官网手机-betway官网体育-betway必威app下载ocessName, 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 apps = mProcessNames.getMap().valueAt(ip); final int NA = apps.size(); for (int ia=0; 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>();

常识延伸:SparseArray和ArrayMap是Android专门针对内存优化而规划的替代Java API中的HashMap的数据结构。

关于key是int类型则运用SparseArray,可防止主动装箱进程;
关于key为其他类型则运用ArrayMap。
HashMap的查找和刺进时刻复杂度为O(1)的价值是献身很多的内存来完结的,而SparseArray和ArrayMap功用略逊于HashMap,但更节约内存。

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

 public E get(String name, int uid) { SparseArray 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()依据app(IBinder类型)来查询相应的方针方针ProcessRecord。

有了进程记载方针ProcessRecord和进程名processName,则进入履行Crash处理办法 AppErrors.java,持续往下看。

四、handleApplicationCrashInner 处理剖析

ActivityManagerService.java

 void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
ApplicationErrorReport.Cra标签14shInfo crashInfo) {
... ...
//将错误信息追加到DropBox
addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);
//【见末节5】
mAppErrors.crashApplication(r, crashInfo);
}

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

五、APP Error info剖析

AppErrors.java
AppErrors 首要是 操控APP Crash的场景条件。

 void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
... ...
try {
// 调用内部 crashApplicationInner办法
crashApplicationInner(r, crashInfo, callingPid, callingUid);
} finally {
Binder.restoreCallingIdentity(origId);
}
}

crashApplicationInner内部办法

 void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,
int callingPid, int callingUid) {
... ...
AppErrorResult result = new AppErrorResult();
TaskRecord task;
synchronized (mService) {
// 假如是通过IActivityController 实例导致的Crash ,则不显现弹窗
// 详见5.1
if (handleAppCrashInActivityController(r, crashInfo, shortMsg, longMsg, stackTrace,
timeMillis, callingPid, callingUid)) {
return;
}
... ...
AppErrorDialog.Data data = new AppErrorDialog.Data();
data.result = result;
data.proc = r;
// 无法必然的进程 也不显现Crash 弹窗【见末节6】
if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, data)) {
return;
}

final Message msg = Message.obtain();
msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG;

task = data.task;
msg.obj = data;
//发送音讯SHOW_ERROR_MSG,弹出提示crash的对话框,等候用户挑选【见末节10】
mService.mUiHandler.sendMessage(msg);
}
//进入堵塞等候,直到用户挑选crash对话框"退出"或许"退出并陈述"
int res = result.get();

Intent appErrorIntent = null;
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res);
if (res == AppErrorDialog.TIMEOUT || res == AppErrorDialog.CANCEL) {
res = AppErrorDialog.FORCE_QUIT;
}
... ...
}

5.1 handleAppCrashInActivityController

handleAppCrashInActivityController,通过IActivityController 实例导致的Crash ,则不显现弹窗.
AppError.java

 private boolean handleAppCrashInActivityController(ProcessRecord r,
ApplicationErrorReport.CrashInfo crashInfo,
String shortMsg, String longMsg,
String stackTrace, long timeMillis,
int callingPid, int callingUid) {
... ...
// 当存在ActivityController的状况,比方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.mContr标签3oller.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标签17.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 =标签14 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(Broadc天外飞仙-betway官网betway官网手机-betway官网体育-betway必威app下载astRecord 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.removeMe天外飞仙-betway官网betway官网手机-betway官网体育-betway必威app下载ssages(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_RO标签14TATION && 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, nul天外飞仙-betway官网betway官网手机-betway官网体育-betway必威app下载l);
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);
}
}