ANR 原理简要分析

最近碰到ANR的问题,需要分析定位。可是ANR的问题是真的难受,有时候即使手握着trace.txt日志也无法看到端倪,因为一般ANR问题出现都伴随着高CPU、高内存占用,确实难以定位。

花了一些时间学习Android ANR 问题的引发和系统如何检测ANR问题,以下做个记录,方便以后追溯,好记性不如烂笔头。

1. ANR问题简介

ANR(App Not Respond)表示程序在一定时间内没有反应。

根本原因就是ui线程长时间无法处理消息或者处理消息时间过长。

2. 常见的ANR问题

主要分成三类

  • InputEvent输入事件: 5s
  • Service服务: 前台服务20s,后台服务200s
  • Broadcast: 前台队列10s,后台队列20s

3. Service 如何检测 ANR 问题

Service的监测ANR是利用定时消息处理的。

在学习Service的启动流程之后你应该知道,AMS是作为一个分发任务的角色,真正处理启动Service的是ActiveServices。

ActiveServices有一个scheduleServiceTimeoutLocked方法,当创建service时候会被调用。

// ActiveService
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
   
    if (proc.executingServices.size() == 0 || proc.thread == null) {
   
        return;
    }
    Message msg = mAm.mHandler.obtainMessage(
            ActivityManagerService.SERVICE_TIMEOUT_MSG);
    msg.obj = proc;
    mAm.mHandler.sendMessageDelayed(msg,
            proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
}

在启动了service以后会不停发一个延迟消息ActivityManagerService.SERVICE_TIMEOUT_MSG

上述代码中,有两个变量:

mAm就是AcivityManagerService,他是由SystemServer启动,运行在独立线程。

mHanlder就是AcivityManagerService的Hanlder,并不运行在AMS的线程中,而是运行在
AMS启动的HandlerThread(名字是MainHandler)。

根据proc.execServiceFg 判断是前台服务还是后台服务,决定延迟时间

// ActiveServices
// 前台服务的ANR时间
static final int SERVICE_TIMEOUT = 20*1000;
// 后台服务的ANR时间
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;

我们看AMS如何处理ActivityManagerService.SERVICE_TIMEOUT_MSG消息

// ActiveServices
void serviceTimeout(ProcessRecord proc) {
   
    String anrMessage = null;
    synchronized(mAm) {
   
        // 当前进程没有运行需要检测的services
        if (proc.executingServices.size() == 0 || proc.thread == null) {
   
            return;
        }
        final long now = SystemClock.uptimeMillis();
        final long maxTime =  now -
                (proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
        ServiceRecord timeout = null;
        long nextTime = 0;
        for (int i=proc.executingServices.size()-1; i>=0; i--) {
   
            ServiceRecord sr = proc.executingServices.valueAt(i);
            // 遍历service并计算service是否超过anr时间
            if (sr.executingStart < maxTime) {
   
                // 找到了一个anr的service
                timeout = sr;
                break;
            }
            if (sr.executingStart > nextTime) {
   
                nextTime = sr.executingStart;
            }
        }
        if (timeout != null && mAm.mLruProcesses.contains(proc
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ANR Trace分析是一种通过分析ANR错误日志(或称为ANR跟踪文件)来确定ANR错误的根本原因的方法。通过分析ANR跟踪文件,您可以了解应用程序中哪些线程阻塞了主线程,并确定导致线程阻塞的原因。 在Android设备上,您可以使用命令行工具 `adb shell dumpsys activity ANR` 来获取ANR错误日志。此命令将打印出最近的ANR错误日志,其中包含了主线程的堆栈跟踪信息、CPU使用情况、线程状态等信息。 下面是一个ANR错误日志的示例: ``` ANR in com.example.myapp PID: 1234 Reason: Input dispatching timed out (Waiting to send non-key event because the touched window has not finished processing certain input events that were delivered to it over 500.0ms ago. Waited for 1.0s.) Load: 98% CPU usage from 10000ms to 0ms ago: 60% com.example.myapp: 50% user + 9.7% kernel / faults: 250 minor 4 major 39% system_server: 14% user + 24% kernel / faults: 324 minor 3 major 0.1% com.android.systemui: 0% user + 0.1% kernel / faults: 17 minor 1 major 0% com.android.phone: 0% user + 0% kernel / faults: 11 minor 0% com.android.launcher: 0% user + 0% kernel / faults: 7 minor 0% kswapd0: 0% user + 0% kernel 0% kworker/u:1: 0% user + 0% kernel ``` 通过分析上面的ANR错误日志,您可以了解以下信息: - 应用程序包名为 com.example.myapp,进程ID为 1234。 - ANR出现的原因是输入事件分发超时,即应用程序在等待某个窗口处理输入事件时超时了。 - 应用程序的CPU负载达到了98%。 - 应用程序占用了60%的CPU时间。 - 系统服务 system_server 占用了39%的CPU时间。 - 其他进程的CPU使用率非常低。 通过分析这些信息,您可以确定ANR错误的原因,并尝试采取相应的措施来解决问题,比如将耗时操作移到后台线程中执行、优化代码、调整系统配置等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值