Android广播发送流程
Posted Zhang Jun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android广播发送流程相关的知识,希望对你有一定的参考价值。
大致流程图
广播发送
常见的通过ContextImpl.java发送广播的方法有下面几种
=> sendBroadcast/sendBroadcastAsUser
:普通的广播发送,默认是当前userId,带有AsUser
的是发送给特定的user
=> sendBroadcastMultiplePermissions/sendBroadcastAsUserMultiplePermissions
:带有多个权限的广播发送
=> sendOrderedBroadcast/sendOrderedBroadcastAsUser
:发送order
有序的广播(order
广播是一个接收完成下一个才能接收,接收者一个个按顺序接收)
=> sendStickyBroadcast/sendStickyBroadcastAsUser
:发送粘性广播,粘性广播的意思是注册者注册了就马上能收到该类型(之前已经发送的粘性广播)的广播,接收者的注册不需要在发送者的前面
=> sendStickyOrderedBroadcast/sendStickyOrderedBroadcastAsUser
:发送粘性而且是顺序order
的广播
系统处理广播发送
-
AMS
接收广播的请求系统
AMS
通过broadcastIntentWithFeature
接收广播的请求 -
修改增加默认
flag
解析可选广播参数BroadcastOptions
- 如默认会增加
FLAG_EXCLUDE_STOPPED_PACKAGES
,不让stop
(如通过forcestop
会设置)的三方app
接收静态广播 - 根据是否粘性广播输出类似的日志:
Broadcast (sticky) intent ordered=(true/false) userid=(userId)
- 解析
BroadcastOptions brOptions
广播可选参数
- 如默认会增加
-
保护广播
isProtectedBroadcast
、特定action
的处理- 识别是否保护广播,这类广播不能给系统之外的
app
调用;而系统尽量发送保护广播,不然也会发出警告 - 后台是否可以接收广播的识别(如果在
system/etc
、/product/etc
等地方加入allow-implicit-broadcast
的广播则可以让后台接收,会加上FLAG_RECEIVER_INCLUDE_BACKGROUND
的flag
) - 特定
action
如包状态改变等的广播的处理
- 识别是否保护广播,这类广播不能给系统之外的
-
发送粘性广播的处理
- 将粘性广播添加到
AMS的mStickyBroadcasts
(key
是用户组,value
是粘性广播列表stickies
)中,单个用户组的粘性广播列表stickies
(key
是action
,value
是intent
) - 已经发送的粘性广播会放入
AMS的mStickyBroadcasts
中,后面动态注册的接收者就可以在注册的时候就接收这类粘性广播, 因为系统有保存这类广播
- 将粘性广播添加到
-
筛选出静态广播接受者
- 这里主要是通过
collectReceiverComponents
来筛选出静态广播接受者 collectReceiverComponents
:收集静态接收者的函数,其调用的是PMS
的queryIntentReceivers
进行查询,然后进行相应过滤。
=> 调用的是PMS
的queryIntentReceivers
进行查询
=> 判断是否只发送到单个用户FLAG_SYSTEM_USER_ONLY
(多用户场景使用),如果是则进行过滤,只发送给单个用户
=> 如果带有broadcastAllowList
(允许接收该广播uid的列表),则只让特定uid列表的静态接收者接收- PMS通过包安装信息获得静态接收者
=> 如果包发送给特定组件,则通过mComponentResolver的mReceivers.mActivities
获取ParsedActivity
,并最终得到对应的ActivityInfo
=> 如果没有指定特定组件和特定包,则通过mComponentResolver
查询recevier
,调用的是IntentResolver
的queryIntent
,根据各类Filter去查询,如mActionToFilter
,查询到结果后在通过buildResolveList
构建返回的结果List result
=> 如果是发送给特定包,则通过mPackages
(安装的时候保存的,key
是包名,value
是androidPackage/ParsingPackageImpl/PackageImpl
)获取AndroidPackage(ParsingPackageImpl)
,通过ParsingPackageImpl
得到这个包的receivers(pkg.getReceivers())
,然后通过mComponentResolver
的queryReceivers(ComponentResolver.java)
->mReceivers.queryIntentForPackage
->queryIntentFromList(IntentResolver.java)
->buildResolveList
此处queryIntentFromList
只查询这个包的receivers
(构建Pair<ParsedActivity, ParsedIntentInfo>
来查询)
在这里可以看到用来保存静态注册广播组件的mComponentResolver
、mReceivers.mActivities
、receivers
- 这里主要是通过
-
筛选出动态广播接受者
动态广播注册其实最终构建的是BroadcastFilter bf
,并放入mReceiverResolver
中去,而放入mReceiverResolver
使用的方法是IntentResolver
的addFilter
-
非
order
的平行广播的入队与分发
如果没有设置ordered
(也称之为serialized
)按顺序,则针对动态注册类型的广播会一次性全部发送出去,于是我们可以看到类似这样的日志:Enqueueing parallel broadcas ***
,这种无需等待APP
的执行,很快系统就处理完了
8.order
广播接收者的过滤
=> 如果设置ordered
(也称之为serialized
)按顺序,不管是动态还是静态的注册者都是放入order
的广播里面发送
=> 如果没有设置ordered
,则只放入静态接收者。(普通的广播会有2个队列发送,一个是parallel broadcast
,一个是ordered broadcast
)
=> 最终不管是静态还是动态注册的广播,只要是需要order
发送的都会合并到receivers
中,排序是按照优先级(android:order/IntentFilter.setPriority
设置的优先级)广播发送时看到类似这样的日志:
Enqueueing ordered broadcast ***
,需要按顺序执行,前面一个接收者执行完成后才能让后面的继续执行,同时前面的可以中断后面接收者的执行
广播的拓展使用
一般广播的应用有3类:
- 针对高配置的设备:
VIP
广播,给一些关键的进程,关键的广播,放入特定的队列,不会由于本身广播队列阻塞了其广播分发,达到比较高效的分发 - 针对低配置的设备:
=> 延迟广播,间隔分发广播等。主要是广播如平行广播一次性发给所有进程,会导致系统负担;
或者是发送给静态注册者需要启动应用,启动多个应用的时候会导致系统负载过重,可以将类似广播延迟分发。
这个总负载还是一样的,只是分散开来,降低持续卡顿情况,至于偶发的峰值卡顿还是存在,需要别的方法配合,场景如开机、切换语言等
=> 限制广播:如在特定场景限制启动,限制接收等行为,降低系统负载。
这类方法效果立竿见影,不过场景需要非常慎重,不然导致功能使用可能出现异常
=> 其它应用:特定场景修改超时时间,让用户感知的anr减少;针对用户不可见的anr
,看一下是否需要用户感知等;接受者优先级调整等。 - 各类广播无法接收问题的解决等可以考虑动态打开一些基本的调试广播开关
DEBUG_BROADCAST
,DEBUG_BROADCAST_BACKGROUND
,DEBUG_BROADCAST_DEFERRAL
,DEBUG_BROADCAST_LIGHT
,DEBUG_BACKGROUND_CHECK
- 目前有3个广播队列,一个是
前台
、一个是后台
、一个是Offload
的广播队列,其中前台广播超时时间是10s
,后台是60s
,Offload
的广播也是60s
以上是关于Android广播发送流程的主要内容,如果未能解决你的问题,请参考以下文章