笔记
- 首先想Looper为什么要执行死循环 Looper运行main线程的,Looper的死循环导致主线程不能结束。 Android中四大组件以及View绘制都运行在主线程的,而如果主线程都结束了,那这些活动如何运行呢? 所以Looper死循环其中一个原因是为了让主线程不结束, 第二个原因让后续活动基于Looper机制来运行。
- 再来回答下Looper死循环为什么不会导致应用卡死?
应用卡死也就是发生ANR,那什么是ANR?ANR是如何检测的,知道了ANR是如何检测的,我们就知道Looper死循环为什么不会导致应用卡死?
什么是ANR?
ANR指的是应用无响应,ANR主体实现在系统层。所有与ANR相关的消息,都会经过系统进程(AMS)调度,然后派发到应用进程完成对消息的实际处理,同时,系统进程设计了不同的超时限制来跟踪消息的处理。 一旦应用程序处理消息不当,超时限制就起作用了, 它收集一些系统状态,比如CPU/IO使用情况、进程函数调用栈,并且报告用户有进程无响应了(ANR对话框)。
ANR机制分为ANR检测机制和ANR报告机制?
- ANR的监测:Android对于不同的ANR类型(Broadcast, Service, InputEvent)都有一套监测机制。
- ANR的报告:在监测到ANR以后,需要显示ANR对话框、输出日志(发生ANR时的进程函数调用栈、CPU使用情况等)。
ANR是如何检测的?
这里以启动Service为例
Service ANR 的监测机制
在Service启动时,最终会调用ActiveServices#realStartServiceLocked。realStartServiceLocked方法实现如下:
private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException {
//最终会调用scheduleServiceTimeoutLocked方法来触发ANR检测。
//此时检测的是Service#OnCreate方法调用时长。其他检测还有onBind..onDestory等等
bumpServiceExecutingLocked(r, execInFg, "create");
...
//启动Service
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
...
}
scheduleServiceTimeoutLocked方法实现如下:
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
...
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
//execServicesFg 代表的是否是前台进程启动的Service。
//如果是前台进程启动Service,超时时间是20S,如果是后台进程启动的Service超时时间是200S
mAm.mHandler.sendMessageDelayed(msg,
proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
}
Service创建完成后会调用ActivityService#serviceDoneExecutingLocked方法移除启动前的检测超时。如在超时时间内Service没有创建完成。会触发AMS#MainHandler中发送的超时检测消息。该消息中调用ActivityService#serviceTimeout方法来告知Service已经超时,最终调用AMS#AppErrors#appNotResponding方法记录ANR日志,并弹出ANR弹窗
//AMS#MainHandler中处理ARN超时
case SERVICE_TIMEOUT_MSG: {
...
mServices.serviceTimeout((ProcessRecord)msg.obj);
}
void serviceTimeout(ProcessRecord proc) {
...
if (anrMessage != null) {
//ANR日志记录并弹出ANR弹窗
mAm.mAppErrors.appNotResponding(proc, null, null, false, anrMessage);
}
}
结论,ANR检测与抛出是一种处理应用卡死的手段,而Looper死循环为什么不会导致应用卡死和ANR半毛钱关系都没有,一个让主线程阻塞,是为了让后续所有活动基于消息机制都运行在主线程中。一个是在Looper中调度的Message时处理的耗时检测。