Android ANR机制的原理以及问题分析(三)

本文详细探讨了Android应用中Broadcast Timeout类型的ANR(应用无响应)机制,包括Broadcast的超时设定、定时器操作、如何重置定时器以及触发ANR的条件。通过对ActivityManagerService源码的分析,揭示了广播队列处理可能导致的性能影响,并提出了监控广播处理时间的建议。
摘要由CSDN通过智能技术生成

一、前言

上一篇我们对Service类型的ANR做了介绍,本篇我们将集合源码,对四种ANR类型中的Broadcast Timeout类型的触发机制做详尽的介绍。

二、Broadcast Timeout

在ActivityManagerService 中,构造了两种Broadcast timeout,分别是 前台FG 10s和
后台BG 60s.

mFgBroadcastQueue/mBgBroadcastQueue ⽤来表示foreground和background
⼴播队列.
⾸先看下如下⼏个数据的定义:

//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
// How long we allow a receiver to run before giving up on it.
 static final int BROADCAST_FG_TIMEOUT = 10*1000;
 static final int BROADCAST_BG_TIMEOUT = 60*1000;
 mFgBroadcastQueue = new BroadcastQueue(this, mHandler, "foreground",
		BROADCAST_FG_TIMEOUT, false);
 mBgBroadcastQueue = new BroadcastQueue(this, mHandler, "background",
        BROADCAST_BG_TIMEOUT, true);
//frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
/**
 * Lists of all active broadcasts that are to be executed
immediately
 * (without waiting for another broadcast to finish). 
Currently this only
 * contains broadcasts to registered receivers, to avoid
spinning up
 * a bunch of processes to execute IntentReceiver
components. Background-
 * and foreground-priority broadcasts are queued
separately.
 */
 /**
 * 并⾏⼴播队列,可以⽴刻执⾏,⽽⽆需等待另⼀个⼴播运⾏完成,该队列只允
许动态已注册的⼴播,
 * 从⽽避免发⽣同时拉起⼤量进程来执⾏⼴播,前台的和后台的⼴播分别位于独
⽴的队列。
 */
 final ArrayList<BroadcastRecord> mParallelBroadcasts = new
ArrayList<>();
 /**
 * List of all active broadcasts that are to be executed
one at a time.
 * The object at the top of the list is the currently
activity broadcasts;
 * those after it are waiting for the top to finish. As
with parallel
 * broadcasts, separate background- and foreground-priority
queues are
 * maintained.
 */
 /**
 *有序⼴播队列,同⼀时间只允许执⾏⼀个⼴播,该队列顶部的⼴播便是活动⼴
播,
 *其他⼴播必须等待该⼴播结束才能运⾏,和并⾏⼴播队列⼀样也是独⽴区别前
台的和后台的⼴播。
 */
 final ArrayList<BroadcastRecord> mOrderedBroadcasts = new
ArrayList<>();
三、Broadcast 设置 定时器

调⽤ processNextBroadcast来处理⼴播.其流程为先处理并⾏⼴播,再处理当前有序
⼴播,最后获取并处理下条有序⼴播.

//frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
BroadcastQueue(ActivityManagerService service, Handler handler,
 		String name, long timeoutPeriod, boolean
		allowDelayBehindServices) {
   
	 mService = service;
	 mHandler = new BroadcastHandler(handler.getLooper());
	 mQueueName = name;
	 mTimeoutPeriod = timeoutPeriod;
	 mDelayBehindServices = allowDelayBehindServices; 
} 

processNextBroadcast 最终会调⽤processNextBroadcastLocked (fromMsg
=false).
此处mService为ActivityManagerService,整个流程还是⽐较⻓的,全程持有AMS
锁,这个⽅法⽐较⻓,我省略的部分不在这⾥重点关注的部分.所以⼴播的队列很⻓的
话,直接会严重影响这个⼿机的性能与流畅度,这⾥可以做⼀个监控,看看系统处理⼴
播都需要hold 多久的ams lock.

整个processNextBroadcast的流程⼤致分为下⾯⼏个步骤:

  1. 设置⼴播超时延时消息,设置定时器: setBroadcastTimeoutLocked:
  2. 处理并⾏⼴播 mParallelBroadcasts 执⾏
    deliverToRegisteredReceiverLocked
  3. 处理有序⼴播mOrderedBroadcasts当⼴播接收者等待时间过⻓, now > now >
    r.dispatchTime + (2mTimeoutPeriodnumReceivers) r.dispatchTime + (2mTimeoutPeriodnumReceivers) 则调⽤
    broadcastTimeoutLocked(false) 则强制结束这条⼴播;
 final void processNextBroadcast(boolean fromMsg) {
   
 	synchronized (mService) {
   
 		processNextBroadcastLocked(fromMsg, false);
 	}
 }
 final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
   
 	BroadcastRecord r;
 	//...省略
 	//【1】处理并⾏⼴播 mParallelBroadcasts
 	while (mParallelBroadcasts.size() > 0) {
   
		 r = mParallelBroadcasts.remove(0);
		 r.dispatchTime = SystemClock.uptimeMillis();
		 r.dispatchClockTime = System.currentTimeMillis();
		 final int N = r.receivers.size();
		 for (int i=0; i<N; i++) {
   
			 Object target = r.receivers.get(i);
			 //分发⼴播给已注册的receiver
			 deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
		 }
		 //添加⼴播历史统计
		 addBroadcastToHistoryLocked(r);
	}
	 // Now take care of the next serialized one...
	 // mPendingBroadcast正常情况下是空的,如果不是空,说明当前有需
	要处理的⼴播,⼀般只有在
	 // 等待⽬标进程启动来处理对应的⼴播的情况下会出现,这个情况下就仅
	仅检查进程是否存在.
	 if (mPendingBroadcast != null) {
   
		 boolean isDead;
		 if (mPendingBroadcast.curApp.pid > 0) {
   
			 synchronized (mService.mPidsSelfLocked) {
   
				 ProcessRecord proc =
				 mService.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值