Android源码分析——广播
广播是一种在组件之间进行消息传递的方式。广播机制的实现是基于Binder进程间通信。
Binder进程间通信和广播的差别:Binder中,Client组件和Service组件通信之前必须先获得Service的一个代理对象,Client组件事先要知道Service组件的存在。广播发送者事先是不要知道广播接收者的存在。因此,广播发送者和接收者之间的耦合度较低。
广播是基于消息发布和订阅者模型实现的。
在同等情况下,动态注册的广播接收者要比静态注册的广播接收者优先收到广播。
android.intent.action.SCREEN_OFF android.intent.action.SCREEN_ON,这两个类型的广播只能被动态注册的接收器处理
发送方如何指定该广播可以被谁接收:设置自定义权限。
广播接收者的注册过程
ContextWrapper.registerReceiver
ContextImpl. registerReceiver
ActivityManagerProxy.registerReceiver
ActivityManagerService.registerReceiver
广播的发送过程
广播发送主要过程:
- 广播发送者将一个广播发送给AMS。
- AMS接收到一个广播后,首先找到这个广播的接收者,然后将他们添加到一个广播调度队列中,最后向AMS所在的线程消息队列发送一个类型为BROADCAST_INTENT_MSG的消息。
- 当AMS所在线程消息队列中的BROADCAST_INTENT_MSG消息被处理时,AMS就会从广播调度队列中找到需要接收广播的广播接收者,并将对应的广播发送给他们所在的进程。
- 广播接收者所运行在的应用程序进程接收到AMS发送过来的广播之后,将广播封装成一个消息,并发送到主线程消息队列中。当该消息被处理时,应用程序进程才会将该广播发送给相应的广播接收者处理。
第1步——广播发送者将一个广播发送给AMS:
ContextWrapper.sendBroadcast
ContextImpl.sendBroadcast
ActivityManagerProxy.broadcaseIntent
ActivityManagerService. broadcaseIntent
第2步——查找目标广播接收者
ActivityInfo ai = AppGlobals.getPackageManager().getReceiverInfo(intent.getComponent,
STOCK_PM_FLAGS);
If(ai!=null){
Receivers = new ArrayList();
ResolveInfo ri = new ResolveInfo();
Ri.activityInfo = ai;
Receivers.add(ri);
}
AMS通过消息处理机制将广播转发给目标广播接收者。
AMS将广播(无序或有序)封装为一个广播转发任务,并添加到内部一个有序广播调度队列中。
动态注册广播接收者、静态注册广播接收者两个队列都是按照优先级从高到低的顺序来排列的。
if(curr.getPriority() >= curt.priority)说明如果一个动态注册的目标广播接收者和静态注册的广播接收者的优先级相同,动态注册的接收者排在前面,即先收到广播。
ActivityManagerService.scheduleBroadcastLocked发送一个类型为BROADCAST_INTENT_MSG消息。
第3步——处理AMS发送的消息
Handler.handleMessage
ActivityManagerService.processNextBroadcast
ActivityManagerService.deliverToRegisteredReceiverLocked
如果BroadcastFilter.requiredPermission的值不为null,那么就表示ActivityManagerService需要检查广播发送者的权限。
如果BroadcastRecord对象的成员变量requiredPermission的值不为null,表示AMS需要检查广播接收者的权限。
以上这两个权限是调用AMS成员函数checkComponentPermission来检查对方PID和UID是否符合要求。
ActivityManagerService.performReceiverLocked
第4步——广播接收者处理MSG
ApplicationThread.scheduleRegisteredReceiver
InnerReceiver.performReceive
ReceiverDispatcher.performReceive
Args.run
BroadcastReceiver.onReceive