ANR触发机制分析

news2024/9/29 15:32:51

ANR是一套监控Android应用程序响应是否及时的机制,可以把发生ANR比作是引爆炸弹,那么整个流程包含三部分组成:

  1. 埋定时炸弹:system_server进程启动倒计时,在规定时间内如果目标应用进程没有干完所有的活,则system_server会杀进程。
  2. 拆炸弹:在规定时间内干完所有活,并及时向system_server报告完成,请求解除定时炸弹。
  3. 引爆炸弹:system_server立即封装现场,抓取快照,搜索目标执行慢的罪证(traces),便于后续的案件侦破(调试分析),最后炸毁目标。

常见的anr有service,broadcast,provider以及input。

Service超时机制

在这里插入图片描述

  1. 客户端(App进程)向system_server进程发起启动服务的请求
  2. biner_1线程接收该请求,紧接着向activitymanager线程发送消息,埋下定时炸弹
  3. binder_1通知service所在进程准备开始干活
  4. binder_3收到任务后转交给main线程,加入messagequeue
  5. 完成service启动的生命周期,然后等待sharepreferences持久化
  6. sp执行完成后,立刻向system_server汇报工作已完成
  7. system_server的binder_2收到完成工作的汇报后,立刻拆除炸弹。如果在炸弹倒计时结束前拆除炸弹则相安无事,否则引爆炸弹(触发anr)

Broadcast超时机制

在这里插入图片描述

  1. 客户端(App进程)向system_server进程发起发送广播的请求
  2. biner_1线程接收该请求并转交给activitymanager线程
  3. activitymanager执行任务(processNextBroadcast方法)的过程埋下定时炸弹
  4. activitymanager通知receiver进程(上面图片有误,应该是receiver进程)准备干活
  5. binder_3收到任务后转交给main线程,加入messagequeue
  6. 完成receiver启动的生命周期,发现当前进程还有sp正在执行写入文件的操作,便将向system_server汇报的任务交给sp(queue-work-looper线程)
  7. sp完成数据的持久化,便可以向system_server汇报工作完成
  8. system_server的binder_2收到完成工作的汇报后,立刻拆除炸弹。如果在炸弹倒计时结束前拆除炸弹则相安无事,否则引爆炸弹(触发anr)

注意:sp从8.0开始采用名叫"queue-work-looper"的handle线程,老版本采用newSingleThreadExecutor创建的单线程的线程池。
如果是动态广播,或者静态广播没有正在执行持久化操作的sp任务,则不需要经过"queue-work-looper"线程中转,直接由main线程向system_server汇报工作。
sp的apply将修改的数据项更新到内存,然后再异步同步数据到磁盘文件,因此很多地方会推荐在主线程调用采用apply方式,避免阻塞主线程,但静态广播超时检测过程需要sp全部持久化到磁盘,如果过度使用apply会增大anr的概率。

Provider超时机制

provider的超时是在provider进程首次启动的时候才会检测,在provider进程已启动的场景,再次请求provider并不会触发provider超时。
在这里插入图片描述

  1. 客户端(App进程)向中控系统(system_server进程)发起获取内容提供者的请求
  2. 中控系统派出一名空闲的通信员(binder_1)接收该请求,检测到内容提供者尚未启动,则先通过zygote孵化新进程
  3. 新化的provider进程向中控系统注册自己的存在
  4. 中控系统的通信员2号接收到该信息后,向组件管家(ActivityManager线程)发送消息,埋下炸弹
  5. 通信员2号通知工地(provider进程)的通信员准备开始干活
  6. 通讯员4号(binder_4收到任务后转交给包工头(main主线程),加入包工头的任务队列(MessageQueue)
  7. 包工头经过一番努力干完活(完成provider的安装工作后向中控系统汇报工作已完成
  8. 中控系统的通讯员3号(binder_3)收到包工头的完工汇报后,立刻拆除炸弹。如果在倒计时结束前拆除炸弹则相安无事,否则会引发爆炸(触发ANR)

input超时机制

input的超时检测机制跟service、broadcast、provider截然不同,为了更好的理解input过程先来介绍两个重要线程的相关工作:

  • InputReader线程负责通过EventHub(监听目录/dev/input)读取输入事件,一旦监听到输入事件则放入到InputDispatcher的mlnBoundQueue队列,并通知其处理该事件;
  • InputDispatcher线程负责将接收收到的输入事件分发给目标应用窗口,分发过程使用到3个事件队列
    1. mlnBoundQueue用于记录InputReader发送过来的输入事件;
    2. outBoundQueue用于记录即将分发给目标应用窗口的输入事件
    3. waitQueue用于记录已分发给目标应用,且应用尚未处理完成的输入事件;
      input的超时机制并非时间到了一定就会爆炸,而是处理后续上报事件的过程才会去检测是否该爆炸,所以更像是扫雷的过程,具体如下图所示。
      在这里插入图片描述
  1. InputReader线程通过EventHub监听底层上报的输入事件,一旦收到输入事件则将其放至mlnBoundQueue队列,并唤醒InputDispatcher线程
  2. InputDispatcher开始分发输入事件,设置埋雷的起点时间。先检测是否有正在处理的事件(mPendingEvent)如果没有则取出mnBoundQueue队头的事件,并将其赋值给mPendingEvent,且重置ANR的timeout;否则不会从mlnBoundQueue中取出事件,也不会重置timeout。然后检查窗口是否就绪
    (checkWindowReadyForMorelnputLocked),满足以下任一情况,则会进入扫雷状态(检测前一个正在处理的事件是否超时),终止本轮事件分发,否则继续执行步骤3。
    • 对于按键类型的输入事件,则outboundQueue或者waitQueue不为空
    • 对于非按键的输入事件:则waitQueue不为空,且等待队头时间超时500ms
  3. 当应用窗口准备就绪,则将mPendingevent转移到outBoundQueue队列
  4. 当outBoundQueue不为空,且应用管道对端连接状态正常,则将数据从outboundQueue中取出事件,放入aitQueue队列
  5. InputDispatcher通过socket告知目标应用所在进程可以准备开始干活
  6. App在初始化时默认已创建跟中控系统双向通信的socketpair,此时App的包工头(main线程)收到输入事件后会层层转发到目标窗口来处理
  7. 包工头完成工作后,会通过socket向中控系统汇报工作完成,则中控系统会将该事件从waitQueue队列中移除。

input超时机制为什么是扫雷,而非定时爆炸呢?是由于对于input来说即便某次事件执行时间超过timeout时长,只要用户后续在没有再生成输入事件,则不会触发ANR。这里的扫雷是指当前输入系统中正在处理着某个耗时事件的前提下,后续的每一次input事件都会检测前一个正在处理的事件是否超时(进入扫雷状态),检测当前的时间距离上次输入事件分发时间点是否超过timeout时长。

前台与后台服务

系统对前台服务启动的超时为20s,而后台服务超时为200s,那么系统是如何区别前台还是后台服务的?
在startservice过程根据发起方进程所属的进程调度组来决定被启动的服务是属于前台还是后台。当发起方进程不等于ProcessList.SCHED_GROUP_BACKGROUND(后台进程组)则认为是前台服务,否则为后台服务。
进程调度组大体可分为top、前台、后台,进程优先级以及进程调度组算法比较复杂,其对应关系可理解为adj等于0的进程属于top进程组,等于100或200的进程属于前台进程组,>200的进程属于后台进程组,后台进程组对于用户来说基本是无感知的,主要做一些后台工作,分配更少的时间片。
在这里插入图片描述
前台服务准确来说,是指由处于前台进程调度组的进程发起的服务。这跟常说的fg-service服务有所不同,fg-service是指挂有前台通知的服务。

前台与后台广播超时

根据发送广播sendBroadcast(Intent intent)中的intent的flags是否包含FLAG_RECEIVER_FOREGROUND来决定把该广播是放入前台广播队列或者后台广播队列,前台广播队列的超时为10s,后台广播队列的超时为60s,默认情况下广播是放入后台广播队列,除非指明加上FLAG_RECEIVER_FOREGROUND标识。
后台广播比前台广播拥有更长的超时值,同时在广播分发过程遇到后台service的启动(mDelayBehindsenvices)会延迟分发广播,等待service的完成,因为等待service而导致的广播ANR会被忽略掉;后台广播属于后台进程调度组,而前台广播属于前台进程调度组。简而言之,后台广播更不容易发生ANR,同时执行的速度也会更慢。
另外,只有串行处理的广播才有超时机制,因为接收者是串行处理的,前一个receiver处理慢,会影响后一个
receiver;并行广播通过一个循环一次性向所有的receiver分发广播事件,所以不存在彼此影响的问题,则没有广播超时。
前台广播准确来说,是指位于前台广播队列的广播

前台与后台ANR

决定是前台还是后台anr取决于该应用发生anr时对用户是否可感知,比如拥有当前前台可见的activity的进程,或者拥有前台通知的fg-service进程,这些是用户可感知的场景;后台anr只抓取发生无响应进程的trace,也不会收集cpu信息,并且会在后台直接杀掉该无响应的进程,前台anr准确来说,是指对用户可感知的进程发生的anr。

后记

  • 哪些路径会引发anr?
    从埋下定时炸弹到拆炸弹之间的任何一个或多个路径执行慢都会导致anr。
  • 发生anr时从trace来看主线程却处于空闲状态或者停留在非耗时代码的原因有哪些?
    可以是抓取trace过于耗时而错过现场,可以是主线程消息队列堆积大量消息而最后抓取快照一刻只是瞬时状态,可以是广播的"queue-work-looper"一直在处理sp操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/174523.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QEMU之一调试uboot(vexpress-a9)

u-boot版本:u-boot-2017.05开发板:vexpress-a9(没办法,目前看到的都是这个开发板,想QEMU调试tiny210,一直没看到怎么修改qemu)编译u-boot:make ARCHarm CROSS_COMPILEarm-linux-gnueabi- vexpre…

Avast 发布免费的 BianLian 勒索软件解密器

安全软件公司 Avast 发布了 BianLian 勒索软件的免费解密器,以帮助恶意软件的受害者在不向黑客支付费用的情况下恢复锁定的文件。 在 2022 年夏天 BianLian 勒索软件的活动增加后大约半年,该威胁组织入侵了多个知名组织,解密器的可用性就出现…

swagger(前言技术)

目录 一、swagger简介 1.前后端分离的特点 2.在没有swagger之前 3.swagger的作用 4.swagger的优点 二、swagger入门 1.新建springboot项目 2.集成swagger 3.开发一个controller用于测试 5.启动服务,验证集成效果 三、swagger常用注解 四、swagger使用综…

2022年PTA行业研究报告

第一章 行业概况 PTA是精对苯二甲酸(Pure Terephthalic Acid)的英文简称,在常温下是白色粉状晶体, 无毒、易燃,若与空气混合,在一定限度内遇火即燃烧。 PTA是重要的大宗有机原料之一,广泛用于化学纤维、轻…

【数据结构入门】-线性表之顺序表(1)

个人主页:平行线也会相交 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【数据结构】 从今天开始,就正式进入数据结构的大门了,把握机会,好好学习,加油。 本文目录…

Arduino环境下对NodeMCU ESP8266将文件直接传入flash的三种方式

flash存储简答介绍 参考:https://www.elecfans.com/consume/572040.html flash存储器又称闪存(快闪存储器),就其本质而言,flash存储器属于EEPROM(电擦除可编程只读存储器)类型。是一种长寿命的…

Java多线程案例之单例模式

目录 一、饿汉模式 二、懒汉模式 前言:单例模式是校招中最常见的设计模式之一。下面我们来谈谈其中的两个模式:懒汉,饿汉。 何为设计模式? 设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多…

【涂鸦蓝牙SDK】基于涂鸦蓝牙SDK数据传输与函数接口解析

基于涂鸦蓝牙SDK数据传输与函数接口解析1.【数据初始化部分】2.【蓝牙状态机控制】3.【数据广播过程】4.【涂鸦平台申请设备以及SDK】5.【涂鸦SDK模组源码思路解析】---- 重要:5.1 数据收发5.【移植涂鸦评估】2023.1.21 本文是基于涂鸦SDK的低功耗蓝牙BLE协议的数据…

Linux创建解压后的应用程序的桌面快捷方式

下面用一个例子演示,其他应用也差不多 下载好的安装文件为.tar.xz格式,通常默认在系统的下载文件夹下(按你实际路径)。右键点击文件,在下拉框中点击提取到此处(意思就是解压)。 解压后&#xff…

DocArray 0.21.0版本发布!新增OpenSearch后端存储,支持Redis后端存储的多语言文本搜索!...

github.com/docarray/docarrayDocArray 是一个用于处理、传输和存储多模态数据的 Python 工具包。DocArray 提供便捷的多模态数据处理功能,具备基于 Protobuf 提供高性能的网络传输性能,同时也为多种向量存储方案提供统一的 API 接口。💡 Doc…

三十三、Kubernetes中Service详解、实例第三篇

1、概述 在kubernetes中,pod是应用程序的载体,我们可以通过pod的ip来访问应用程序,但是pod的ip地址不是固定的,这也就意味着不方便直接采用pod的ip对服务进行访问。 为了解决这个问题,kubernetes提供了Service资源&…

06.动态内存管理

1. 存在动态内存分配的原因我们已经掌握的内存开辟方式有:int val 20;//在栈空间上开辟四个字节 char arr[10] { 0 };//在栈空间上开辟10个字节的连续空间//写死了 //变长数组,int arr[n],变量的方式可以指定大小,并非意味着数组…

0th HPC Game小结

PART 1 - 基础知识 一、文件读取 二进制文件 mmap https://hpcgame.pku.edu.cn/demo/scow/api/proxy/relative/192.168.100.61/35515/ fread fwrite //readFILE* fi;if(fi fopen("input.bin", "rb")){fread(&p, sizeof(int), 1, fi);fread(&n,…

RabbitMQ之消息转换器

前言:大家好,我是小威,24届毕业生,曾经在某央企公司实习,目前在某税务公司。本篇文章将记录和分享RabbitMQ消息转换器的知识点。 本篇文章记录的基础知识,适合在学Java的小白,也适合复习中&…

深入理解机器学习——关联规则挖掘:基础知识

分类目录:《深入理解机器学习》总目录 许多商业企业在日复一日的运营中积聚了大量的数据。例如,食品商店的收银台每天都收集大量的顾客购物数据。下图给出一个这种数据的例子,通常称作购物篮事务(Market Basket Transaction&#…

Elasticsearch基本使用初体验01

ElasticSearch是一款非常强大的、基于Lucene的开源搜索及分析引擎;它是一个实时的分布式搜索分析引擎,它能让你以前所未有的速度和规模,去探索你的数据。 1.es的安装 工欲善其事,必先利其器;想要学es,我们…

九龙证券|磷酸铁锂电池包和铅酸电池有哪些区别?

目前,新能源汽车电动车一般用的电池有3种,铅酸蓄电池、镍氢充电电池、锂离子电池。伴随着电动车蓄电池技能工艺的升级换代,锂电池的发展壮大和应用领域日益持续上升。那么,磷酸铁锂电池包和铅酸电池有哪些差异呢?铅酸蓄…

PowerShell 美化(oh-my-posh)

文章目录PowerShell 美化一、 添加右键菜单1、 修改默认右键菜单2、 寻找安装目录3、 修改注册表二、 样式修改1、 环境安装2、 配置使用PowerShell 美化 一、 添加右键菜单 1、 修改默认右键菜单 直接使用这个命令可以将 win11 的右键菜单修改为 win10 的右键菜单&#xff1…

基础数学(三)位运算 JZ 15.位1的个数

正在刷DFS相关题的时候突然间,给我蹦出来这样一个回溯题: 401. 二进制手表 二进制手表顶部有 4 个 LED 代表 小时(0-11),底部的 6 个 LED 代表 分钟(0-59)。每个 LED 代表一个 0 或 1&#xff…

maven 解决Cannot access alimaven以及Process terminated

maven 解决Cannot access alimaven以及Process terminated 目录maven 解决Cannot access alimaven以及Process terminated方案一:用idea打开settings.xml,更正红色报错方案二:将IDEA的Maven默认版本更换成你下载的maven文件夹方案三&#xff…