当前位置:   article > 正文

Android ANR机制的原理以及问题分析(三)_broadcastqueue: timeout of broadcast broadcastreco

broadcastqueue: timeout of broadcast broadcastrecord{b5eb714 u0 android.inte

一、前言

上一篇我们对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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
//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<>();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
三、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; 
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/989650
推荐阅读
相关标签
  

闽ICP备14008679号