深入理解 Android 9.0 Crash 机制(一)
极力推荐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 Crash和 Framework Crash(包含app crash在内),对于Crash
相信很多app开发者都会遇到,那么上层什么时候会出现Crash呢,系统又是如何处理Crash
的呢。例如,在app大家经常使用try...catch
语句,那么如果没有有效catch exception
,就是导致应用Crash,发生没有catch exception
,系统便会来进行捕获,并进入Crash
流程。如果你是从事Android系统开发或者架构相关工作,或者遇到需要解系统性的疑难杂症,那么很有必要了解系统Crash
处理流程,知其然还需知其所以然;如果你仅仅是App初级开发,可能本文并非很适合阅读,整个系统流程错综复杂。
在Android系统启动系列文章,已讲述过上层应用都是由Zygote fork孵化而来,分为system_server系统进程和各种应用进程,在这些进程创建之初会设置未捕获异常的处理器,当系统抛出未捕获的异常时,最终都交给异常处理器。
- 对于
system_server
进程:system_server
启动过程中由RuntimeInit.java
的commonInit
方法设置UncaughtHandler
,用于处理未捕获异常; - 对于普通应用进程:进程创建过程中,同样会调用
RuntimeInit.java
的commonInit
方法设置UncaughtHandler
。
1.1 crash调用链
crash流程的方法调用关系如下:
AMP.handleApplicationCrash
AMS.handleApplicationCrash
AMS.findAppProcess
AMS.handleApplicationCrashInner
AMS.addErrorToDropBox
AMS.crashApplication
AMS.makeAppCrashingLocked
AMS.startAppProblemLocked
ProcessRecord.stopFreezingAllLocked
ActivityRecord.stopFreezingScreenLocked
WMS.stopFreezingScreenLocked
WMS.stopFreezingDisplayLocked
AMS.handleAppCrashLocked
mUiHandler.sendMessage(SHOW_ERROR_MSG)
Process.killProcess(Process.myPid());
System.exit(10);
二、Crash处理流程
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 Thread
的Framework
代码会捕获这些异常。
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>>()
;
知识延伸: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<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_server
的dropbox
文件名为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);
}
}
长按识别二维码,领福利
至此,本篇已结束,如有不对的地方,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢!
如有侵权,请联系小编,小编对此深感抱歉,届时小编会删除文章,立即停止侵权行为,请您多多包涵。