安卓入门五十三 ANR

3.1 ANR 原理

ANR(Application Not Responding)的监测原理本质上是消息机制,设定一个delay消息,超时未被移除则触发ANR。具体逻辑处理都在system server端,包括发送超时消息,移除超时消息,处理超时消息以及ANR弹框展示等;对于app而言,触发ANR的条件是主线程阻塞。

分类

很多情况下对应类型的ANR与正在执行的组件(ContentProvider、Broadcast、Service)本身没有关系。

  1. Service ANR:前台20s,后台200s;startForeground超时10s
  2. Broadcast ANR:前台10s,后台60s
  3. Input ANR:按键或触摸事件在5s内无响应
  4. ContentProvider ANR:10s,少见

常见原因

  1. 主线程binder耗时
  2. 主线程i/o耗时
  3. 死锁
  4. 主线程等锁耗时
  5. activity resume慢/焦点窗口切换慢(针对Input anr)
  6. 主线程有太多消息要执行,导致对应组件消息执行delay。
  7. 主线程前面的消息执行耗时,导致后面的消息delay。
  8. 跟手机当时状态有关,内存/cpu等
  9. startForeground未在Service的onStartCommand中执行

如何分析

步骤

确定anr的基本信息 先搜索am_anr 确定anr发生时间点、类型、超时、进程等。

查看traces文件 查看/data/anr下的对应1中的进程和时间点的traces文件, 如果很明显主线程处于Blocked状态切utm/stm时间较长则可直接通过堆栈确认原因。

查看对应时间段的event log/ main log等 但是很多情况下并不能恰如其分抓到anr发生时的堆栈,所以还得通过其他log来确认原因。 搜索 “ANR in”往前时间点搜索pid 相关信息(在03-04 13:45:03.781 往前推8s时间内)

关键字眼

  1. Slow Operation /am_lifecycle_sample
  2. Slow Looper main
  3. Slow Binder /binder_sample
  4. dvm_lock_sample

常见实例

i/o耗时

io耗时导致110消息执行时间过长,导致Receiver消息迟迟得不到执行

Service的startFrouground使用不当

startForeground一般需要在onStartCommand方法里调用,而不是在Service的onCreate中。因为如果你onStartCommand的返回值是START_NOT_STICKY,进程被杀后重启不会回调onCreate方法,但是还是会有还会走ANR的逻辑。

进程crash后不会立刻拉起Service,而是通过计算delay去启动,此处delay时间是6268ms,log中正好6s后才开始通过MxActivateService拉起短信进程

startForeground ANR的超时时间是10s,计算时间起始点是system server端post app端去执行Service的onStartCommand时。如果在onStartCommand开始执行后10s内未调用startForeground方法就会发生ANR。

主线程等锁耗时

发生ANR的8s内,home主线程有等锁11s,导致input事件未被及时处理。

binder 耗时

app查询另一个进程的content provider,binder耗时5s多

对端进程pid为7467,isLocked持锁5s多,导致isOpen等锁

activity resume慢/焦点窗口切换慢

09-18 18:22:46.380 system server端已经post app执行

TransparentAliuserGuideActivity启动流程(onCreate、onStart、onResume)

在2021-09-18 18:22:52打印anr traces时(6s后),activity还在执行onCreate,app主线程resume慢

复杂场景

app主线程等锁0x083a79bd处于Blocked状态

该锁0x083a79bd被Ad-SingleThread线程持有,且线程当前正在等待binder对端响应

查看traces中system server进程,搜索getContentProvider找到对应的binder线程

查找AMS中上述堆栈对应代码 这段代码是在等待对应provider发布完成,如果provider所在进程未启动,则先拉起该进程;超时时间为20s。

结合对应时间点的对端(Content Provider所在)进程的event log

综上:content provider拉起进程时,进程刚拉起尚未publish provider就被杀死,所以getContentProviderImpl 等待耗时,导致bindet耗时,app端子线程持锁耗时,主线程等锁耗时,从而发生ANR。

ANR 原理

Service ANR

system server在service的相关流程执行前会发送delay消息到main handler中,如果app段在对应delay消息内未通知system server段移除消息,则执行超时消息,触发anr。 SERVICE_TIMEOUT_MSG delay时间为前台service 20s,后台service 200s

service的anr主要总结为如下表格中的三个流程:

原因/流程

ActiveServices

Service

超时时间

create

realStartServiceLocked

onCreate

20s/200s

start

sendServiceArgs

onStartCommand

20s/200s

foreground

sendServiceArgs

onStartCommand

10s

创建service

发送delay消息

在ActiveService的realStartServiceLocked方法中发送delay消息,前台20s,后台200s;再去通知app端执行create service相关流程。

移除delay消息

app端收到system server的binder回调scheduleCreateService后,发送消息到主线程的Handler,等到、Service的onCreate方法执行完后,通过binder serviceDoneExecuting告知system server执行完毕,移除MainHandler中相关的delay消息。

启动service

发送delay消息

system server在start service前post一个SERVICE_TIMEOUT_MSG delay消息到MainHandler, 对应system server的是sendServiceArgsLocked方法,对应app端的是onStartCommand方法。

startService时,若service存在,即已进被创建,则直接调用sendServiceArgsLocked方法,否则等service create之后再调用该方法。

移除delay消息

app端收到system server的binder回调scheduleServiceArgs后,发送消息到主线程的Handler,等到相关消息被执行,Service的onStartCommand方法执行完后,通过binder serviceDoneExecuting告知system server执行完毕,移除MainHandler中相关的delay消息。

前台service调用startForeground超时

发送delay消息

调用startForegroundService 启动前台Service ,需要在onStartCommand调用前post 一个 delay 10s的SERVICE_FOREGROUND_TIMEOUT_MSG消息到MainHandler中

如果客户端10s内未及时调用startForeground,则会 触发ANR

移除delay消息

客户端调用startForeground

Service.startForeground

→ AMS.setServiceForeground

→ ActiveServices.setServiceForegroundLocked

→ setServiceForegroundInnerLocked

→ MainHandler.removeMessages

执行超时消息,触发ANR

  • 若binder耗时(比较少见);
  • app主线程执行一些消息耗时导致service相关的消息得不到执行 ;
  • 或Service本身的周期方法onCreate,onStartCommand等执行一些耗时操作;

导致20s(前台service)或200s(后台service)或10s(startForeground)内app端未及时binder回调serviceDoneExecuting告知AMS,MainHandler则会执行到delay的消息,并调用appNotResponding方法,造成ANR现象。

MainHandler

→ ActiveServices.serviceTimeout(serviceForegroundTimeout)

→ ProcessRecord.appNotResponding

Broacast超时

发送delay消息 前台广播10s,后台广播60s

BroadcastHandler

→ BroadcastQueue . processNextBroadcast

→ processNextBroadcastLocked

 → setBroadcastTimeoutLocked

 →BroadcastHandler.sendMessageAtTime

移除delay消息

Binder

→ AMS.finishReceiver

→ BroadcastQueue.processNextBroadcastLocked

→ cancelBroadcastTimeoutLocked

 → BroadcastHandler.removeMessages

执行delay消息

BroadcastHandler

→ BroadcastQueue.broadcastTimeoutLocked

 → AppNotResponding.run

→ ProcessRecord.appNotResponding

ContentProvider超时

发送delay消息

Binder

→ AMS.attachApplication

 → attachApplicationLocked

→ MainHandler.sendMessageDelayed

移除delay消息

Binder→ AMS.publishContentProviders → MainHandler.removeMessages

执行delay消息 直接杀死进程以及清理相关信息,不会弹ANR弹窗

MainHandler

 → processContentProviderPublishTimedOutLocked

 → cleanupAppInLaunchingProvidersLocked

→ ProcessList.removeProcessLocked

Input超时

上报堆栈如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值