[Android5.1]Broadcast机制
Posted 迷途小书童Eric
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Android5.1]Broadcast机制相关的知识,希望对你有一定的参考价值。
Broadcast,顾名思义,“广播”。它是android系统的一种通知机制。有广播,当然也得有广播接收器,即Broadcast Receiver。
Broadcast Receiver是一种全局的监听器,用于监听系统全局的广播消息。它可以接收来自系统和应用的广播。应用程序可以使用它对外部事件进行过滤,只对感兴趣的外部事件进行接收并做出响应。
BroadcastReceiver注册方式
静态注册
通过在Manifest文件中声明< receiver >标签实现。在应用程序运行时,系统会利用java反射机制构造一个BroadcastReceiver实例。动态注册
通过调用registerReceiver方法注册。当应用不需要该广播接收器时,需要调用unregisterReceiver来撤销。
广播发送方式
普通发送方式
将广播发送给每一个接收者,所有对该广播内容感兴趣的广播接收器都能收到。串行发送方式
根据接收者的优先级顺序一个一个地发送。只有等上一个广播接收器处理完毕后,后面的广播接收才可以接收到该广播,而且上一个接收器可以将处理结果一块传给下一个。任何一个接收器都可以终止广播的发送,终止后,后面的接收器就收不到该广播了。Sticky发送方式
AMS会保存Sticky类型的广播,当有广播接收器注册时,如果该接收器正好对该广播感兴趣,就会立刻将该广播发送给接收器。
动态注册广播接收器
通过调用ContxtImal类的registerReceiver方法,来注册一个广播接收器。代码如下:
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
return registerReceiver(receiver, filter, null, null);
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler)
return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext());
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission, Handler scheduler, Context context)
...
try
return ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
...
可见,最后通过binder机制调用了AMS的registerReceiver方法。该方法代码如下:
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId)
...
synchronized(this)
ProcessRecord callerApp = null;
if (caller != null)
callerApp = getRecordForAppLocked(caller);
if (callerApp == null) //如果调用进程没有在AMS中注册,则抛异常
throw new SecurityExc eption(...);
// 检查调用进程中是否有callerPackage在运行,否则抛异常
if (callerApp.info.uid != Process.SYSTEM_UID &&
!callerApp.pkgList.containsKey(callerPackage) &&
!"android".equals(callerPackage))
throw new SecurityException(...);
...
List allSticky = null;
// 查找系统中所有匹配IntentFilter的sticky广播,并放在allSticky中
Iterator actions = filter.actionsIterator();
if (actions != null)
while (actions.hasNext())
String action = (String)actions.next();
allSticky = getStickiesLocked(action, filter, allSticky, UserHandle.USER_ALL);
allSticky = getStickiesLocked(action, filter, allSticky, UserHandle.getUserId(callingUid));
else
allSticky = getStickiesLocked(null, filter, allSticky,
UserHandle.USER_ALL);
allSticky = getStickiesLocked(null, filter, allSticky,
UserHandle.getUserId(callingUid));
// 取出allSticky中的第一个Intent,虽然可能有多个sticky广播,但registerReceiver()只返回第一个
Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
if (receiver == null)
return sticky; //如果没有设置接收者,直接返回
// mRegisteredReceivers中保存所有动态注册的接收者,每个接收者对应一个ReceiverList,
// 里面存放了该接收者所有的过滤条件(即BroadcastFilter )
ReceiverList rl = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) //如果第一次注册,肯定为null
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver); // 为该接收者新建一个ReceiverList
if (rl.app != null)
rl.app.receivers.add(rl);
else
try
receiver.asBinder().linkToDeath(rl, 0); //监听广播接收者所在进程的死亡消息
catch (RemoteException e)
return sticky;
rl.linkedToDeath = true;
// 将新建的ReceiverList加入到mRegisteredReceivers中。
// mRegisteredReceivers是一个HashMap,key为IIntentReceiver,value为ReceiverList
mRegisteredReceivers.put(receiver.asBinder(), rl);
...
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId); //根据传入的IntentFilter创建一个BroadcastFilter
rl.add(bf); // 添加到该接收者对应的ReceiverList
...
mReceiverResolver.addFilter(bf); //mReceiverResolver中也存一份,mReceiverResolver存放系统中所有的BroadcastFilter
// allSticky不为空,说明有sticky广播需要立刻处理。
if (allSticky != null)
ArrayList receivers = new ArrayList();
receivers.add(bf);
// 向当前注册的接收者循环发送每一个sticky广播,具体的步骤在后面讲“发送广播”的章节会详细介绍。
int N = allSticky.size();
for (int i=0; i<N; i++)
Intent intent = (Intent)allSticky.get(i);
BroadcastQueue queue = broadcastQueueForIntent(intent); //获取一个合适BroadcastQueue
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, -1, -1, null, null, AppOpsManager.OP_NONE, receivers, null, 0,
null, null, false, true, true, -1); //为每一个sticky广播创建一个BroadcastRecord
queue.enqueueParallelBroadcastLocked(r); //放入对应的BroadcastQueue中
queue.scheduleBroadcastsLocked(); //调度该广播的发送
return sticky;
发送广播
ContxtImal类中定义了一系列的发送广播的接口,如下:
public void sendBroadcast(Intent intent);
public void sendBroadcast(Intent intent, String receiverPermission);
public void sendBroadcast(Intent intent, String receiverPermission, int appOp);
public void sendOrderedBroadcast(Intent intent, String receiverPermission);
public void sendOrderedBroadcast(Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras);
public void sendOrderedBroadcast(Intent intent, String receiverPermission, int appOp, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras);
public void sendStickyBroadcast(Intent intent);
public void sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras);
其中,sendBroadcast是发送普通广播,sendOrderedBroadcast是发送串行广播,sendStickyBroadcast是发送粘性广播。
下面以sendBroadcast为例,分析一下整个流程。代码如下:
public void sendBroadcast(Intent intent, String receiverPermission, int appOp)
...
try
...
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermission, appOp, false, false,
getUserId());
...
sendBroadcast()代码比较简单,通过binder机制,调用AMS的broadcastIntent方法实现广播的发送。
实际上,不管是sendBroadcast()、sendOrderedBroadcast还是sendStickyBroadcast,最终都调用AMS的broadcastIntent方法。
public final int broadcastIntent(IApplicationThread caller,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle map,
String requiredPermission, int appOp, boolean serialized, boolean sticky, int userId)
synchronized(this)
...
int res = broadcastIntentLocked(callerApp, callerApp != null ? callerApp.info.packageName : null,
intent, resolvedType, resultTo, resultCode, resultData, map, requiredPermission, appOp,
serialized, sticky, callingPid, callingUid, userId);
...
进一步调用broadcastIntentLocked方法实现,代码如下:
private final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String requiredPermission, int appOp,
boolean ordered, boolean sticky, int callingPid, int callingUid, int userId)
intent = new Intent(intent);
// 默认情况,不可以向一个“停止的app”发送广播
// 所谓“停止的app”即安装后还没有启动过,或者被用户强制停止了。
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
// 判断发送方是否有权限发送该广播
int callingAppId = UserHandle.getAppId(callingUid);
if (callingAppId == Process.SYSTEM_UID || callingAppId == Process.PHONE_UID
|| callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID
|| callingAppId == Process.NFC_UID || callingUid == 0)
// 如果发送方的Uid为SYSTEM_UID、PHONE_UID或SHELL_UID,或者发送方具有root权限,那么它一定有权力发送广播
else if (callerApp == null || !callerApp.persistent)
try
// 如果是受保护的广播,则抛异常
// 受保护的广播可以在AndroidManifest文件中用<protected-broadcast>标签指定。
if (AppGlobals.getPackageManager().isProtectedBroadcast(intent.getAction()))
throw new SecurityException(msg);
else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(intent.getAction()))
...
catch (RemoteException e)
return ActivityManager.BROADCAST_SUCCESS;
// 检查是否为特殊广播,并作出相应处理。主要是一些PMS发送的package相关的Action,还有是系统广播
final String action = intent.getAction();
if (action != null)
switch (action)
...
// 先处理粘性广播
if (sticky)
//检查调用进程是否有BROADCAST_STICKY权限,没有则抛异常
if (checkPermission(...)
throw new SecurityException(msg);
//检查该广播是否携带权限信息,sticky广播不应该携带,否则直接返回
if (requiredPermission != null)
return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
//检查该广播是否指定接收对象,sticky广播不应该指定,否则抛异常
if (intent.getComponent() != null)
throw new SecurityException(...);
... //多用户处理
//将该广播的intent存放在mStickyBroadcasts中。
//stickies = mStickyBroadcasts.get(UserHandle.USER_ALL)
ArrayList<Intent> list = stickies.get(intent.getAction());
if (list == null)
list = new ArrayList<Intent>();
stickies.put(intent.getAction(), list);
int N = list.size();
int i;
for (i=0; i<N; i++)
if (intent.filterEquals(list.get(i))) //如果已存在,则替换
// This sticky already exists, replace it.
list.set(i, new Intent(intent));
break;
//否则,添加进去。
if (i >= N)
list.add(new Intent(intent));
...
List receivers = null; //保存所有的receiver,包括静态和动态
List<BroadcastFilter> registeredReceivers = null; //只包括动态接收器
//FLAG_RECEIVER_REGISTERED_ONLY:只向动态注册的接收器发送
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0)
//从PMS中收集静态注册的接收器
receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
//注意:如果Intent中指定了目标组件,就没必要解析动态注册接收者了,只需要得到目标组件的ResolveInfo就可以了,
//这个工作在collectReceiverComponents()中就完成了。
if (intent.getComponent() == null) //如果没有指定目标组件
... //多user的处理,这里省去
//对mReceiverResolver进行queryIntent匹配,从而得到动态注册的接收者
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false, userId);
...
//如果设置了FLAG_RECEIVER_REPLACE_PENDING,而且之前的intent没有被处理,则用新的intent替换就的intent
final boolean replacePending =
(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
if (DEBUG_BROADCAST) Slog.v(TAG, "Enqueing broadcast: " + intent.getAction()
+ " replacePending=" + replacePending);
//先处理动态注册接收者
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) //如果该广播不是串行广播,且存在动态注册的接受者
// broadcastQueueForIntent:如果intent中设置FLAG_RECEIVER_FOREGROUND,则返回mFgBroadcastQueue
//否则返回mBgBroadcastQueue
final BroadcastQueue queue = broadcastQueueForIntent(intent);
//新建一个BroadcastRecord,并包含registeredReceivers
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, resolvedType, requiredPermission,
appOp, registeredReceivers, resultTo, resultCode, resultData, map,
ordered, sticky, false, userId);
if (DEBUG_BROADCAST) Slog.v(TAG, "Enqueueing parallel broadcast " + r);
final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
if (!replaced)
queue.enqueueParallelBroadcastLocked(r); //将r添加到BroadcastQueue的变量mParallelBroadcasts中
queue.scheduleBroadcastsLocked(); //发送该广播
registeredReceivers = null; //清除动态注册接收者
NR = 0;
// 将所有静态注册和剩下的动态注册的接收者合并到一个list,即receivers
int ir = 0;
if (receivers != null)
... //处理PACKAGE_ADDED的intent
//根据优先级,将registeredReceivers中的动态注册者合并到receivers中
int NT = receivers != null ? receivers.size() : 0;
int it = 0;
ResolveInfo curt = null;
BroadcastFilter curr = null;
while (it < NT && ir < NR)
if (curt == null)
curt = (ResolveInfo)receivers.get(it);
if (curr == null)
curr = registeredReceivers.get(ir);
//如果动态注册者优先级大于静态注册者,add进去
if (curr.getPriority() >= curt.priority)
// Insert this broadcast record into the final list.
receivers.add(it, curr);
ir++;
curr = null;
it++;
NT++;
else
//否则跳过。这里注意:it加1,但ir没有加1
//这样下次比较优先级时,是下一个静态注册者与当前动态者比较,这样不会错过任何一个动态注册者
it++;
curt = null;
//仍然有动态注册者没有add进去,这里把他们直接放到receivers的列尾。
while (ir < NR)
if (receivers == null)
receivers = new ArrayList(); //如果receivers =null,需要新建一个list
receivers.add(registeredReceivers.get(ir));
ir++;
if ((receivers != null && receivers.size() > 0) || resultTo != null)
BroadcastQueue queue = broadcastQueueForIntent(intent); //查找合适的BroadcastQueue
//新建BroadcastRecord,并包含receivers
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, resolvedType,
requiredPermission, appOp, receivers, resultTo, resultCode,
resultData, map, ordered, sticky, false, userId);
if (DEBUG_BROADCAST) Slog.v(
TAG, "Enqueueing ordered broadcast " + r
+ ": prev had " + queue.mOrderedBroadcasts.size());
if (DEBUG_BROADCAST)
int seq = r.intent.getIntExtra("seq", -1);
Slog.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
if (!replaced)
queue.enqueueOrderedBroadcastLocked(r); //将r添加到BroadcastQueue的变量mOrderedBroadcasts中
queue.scheduleBroadcastsLocked(); //发送该广播
return ActivityManager.BROADCAST_SUCCESS;
从上面的代码可知:
- 使用一个BroadcastRecord类型来描述一个广播,且BroadcastRecord中包含该广播对应的所有接收者。
- BroadcastQueue中有两个成员变量,mOrderedBroadcasts和mParallelBroadcasts,用来保存BroadcastRecord。
final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<BroadcastRecord>();
final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<BroadcastRecord>();
mOrderedBroadcasts和mParallelBroadcasts的区别可以通过下表来描述:
广播类型/接收器注册方法 | 普通广播 | 串行广播 |
---|---|---|
静态注册 | mOrderedBroadcasts | mOrderedBroadcasts |
动态注册 | mParallelBroadcasts | mOrderedBroadcasts |
对于存在动态注册接收器的普通广播,其BroadcastRecord保存在mParallelBroadcasts中。
对于存在静态注册接收器的普通广播和所有的串行广播,其BroadcastRecord保存在mOrderedBroadcasts中。
AMS对广播的发送调度
从发送广播的工作流程可以看到,AMS将广播保存到BroadcastQueue中,然后调用scheduleBroadcastsLocked方法来处理。
public void scheduleBroadcastsLocked()
...
if (mBroadcastsScheduled)
return;
//发送一条BROADCAST_INTENT_MSG消息。
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
该消息会触发processNextBroadcast的执行。代码如下:
public void handleMessage(Message msg)
switch (msg.what)
case BROADCAST_INTENT_MSG:
...
processNextBroadcast(true);
break;
...
这里注意一个细节:mBroadcastsScheduled,=true指示已经调度发送广播了,即processNextBroadcast已经执行了。如果还没有执行,就不用再触发一次了。进入processNextBroadcast()后,马上就将mBroadcastsScheduled置为false。
下面重点分析processNextBroadcast():
final void processNextBroadcast(boolean fromMsg)
synchronized(mService)
BroadcastRecord r;
...
mService.updateCpuStats(); //更新CPU使用状态
if (fromMsg)
mBroadcastsScheduled = false;
//首先发送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);
...
//进一步调用deliverToRegisteredReceiverLocked处理,后面会对该函数进行分析
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
addBroadcastToHistoryLocked(r); //将处理后的广播add到mBroadcastHistory中。
...
/* 以下程序开始处理mOrderedBroadcasts中的广播!*/
// 首先处理mPendingBroadcast中暂存的广播。mPendingBroadcast用于保存因应用进程还未启动,而处于等待状态的广播
// 这段代码我们后面会详细介绍,这里先跳过。
if (mPendingBroadcast != null)
boolean isDead;
synchronized (mService.mPidsSelfLocked)
ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);
isDead = proc == null || proc.crashing;
if (!isDead)
// It's still alive, so keep waiting
return;
else
mPendingBroadcast.state = BroadcastRecord.IDLE;
mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
mPendingBroadcast = null;
boolean looped = false;
do
if (mOrderedBroadcasts.size() == 0) //mOrderedBroadcasts中的广播都处理完毕
// No more broadcasts pending, so all done!
mService.scheduleAppGcsLocked();
if (looped)
mService.updateOomAdjLocked(); //如果最后一个order广播处理完,更新所有app的OOM值
return;
r = mOrderedBroadcasts.get(0); //取出下一个要处理的order广播
boolean forceReceive = false;
//如果该广播的处理时间超过2*(接收者个数*每个接收者超时时间),则强制结束该广播
int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
if (mService.mProcessesReady && r.dispatchTime > 0)
long now = SystemClock.uptimeMillis();
if ((numReceivers > 0) &&
(now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers)))
broadcastTimeoutLocked(false); // 强制结束该广播
forceReceive = true;
r.state = BroadcastRecord.IDLE;
//只有该广播状态为IDLE,才可以继续处理,即发送给下一个接收者。
//上一个接收者在处理完广播后,会调用finishReceiver,该函数会将r.state设置为IDLE
if (r.state != BroadcastRecord.IDLE)
return;
if (r.receivers == null || r.nextReceiver >= numReceivers
|| r.resultAbort || forceReceive)
//如果满足上面几个条件,就说明该广播已经没有接收者了(有可能是广播处理完,也有可能是强制中断)。
//这时,就要根据情况返回广播处理结果
if (r.resultTo != null)
try
performReceiveLocked(r.callerApp, r.resultTo, new Intent(r.intent), r.resultCode,
r.resultData, r.resultExtras, false, false, r.userId);
// Set this to null so that the reference
// (local and remote) isn't kept in the mBroadcastHistory.
r.resultTo = null;
catch (RemoteException e)
r.resultTo = null;
cancelBroadcastTimeoutLocked();
// ... and on to the next...
addBroadcastToHistoryLocked(r);
mOrderedBroadcasts.remove(0); //移除该广播
r = null;
looped = true;
continue;
while (r == null);
// Get the next receiver...
int recIdx = r.nextReceiver++;
r.receiverTime = SystemClock.uptimeMillis();
//recIdx = 0标示这是该广播刚开始处理,因此设置dispatchTime和dispatchClockTime为当前时间
if (recIdx == 0)
r.dispatchTime = r.receiverTime;
r.dispatchClockTime = System.currentTimeMillis();
//设置广播处理超时时间
if (! mPendingBroadcastTimeoutMessage)
long timeoutTime = r.receiverTime + mTimeoutPeriod;
setBroadcastTimeoutLocked(timeoutTime);
Object nextReceiver = r.receivers.get(recIdx); //取出下一个接收者
//如果是动态注册接收者,直接调用deliverToRegisteredReceiverLocked处理
if (nextReceiver instanceof BroadcastFilter) // 因为动态注册接收者类型为BroadcastFilter
BroadcastFilter filter = (BroadcastFilter)nextReceiver;
deliverToRegisteredReceiverLocked(r, filter, r.ordered);
//如果当前接收者已经处理完毕,则立即调用scheduleBroadcastsLocked准备发送给下一个接收者
//这里的“!r.ordered”判断不理解,动态注册的有序接收者应该在mPendingBroadcast中,而且在函数刚开始就处理完了啊??
if (r.receiver == null || !r.ordered)
r.state = BroadcastRecord.IDLE;
scheduleBroadcastsLocked();
return; //因为已经通知接收者处理广播了,因此要等待处理结束。
//处理静态注册接收者,静态注册接收者类型为ResolveInfo
ResolveInfo info = (ResolveInfo)nextReceiver;
ComponentName component = new ComponentName(
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name);
boolean skip = false;
... //各种检查、判断。如果不符合,就设置skip = true,标示跳过该接收者
if (skip)
r.receiver = null;
r.curFilter = null;
r.state = BroadcastRecord.IDLE;
scheduleBroadcastsLocked(); //准备进入下一次发送调度
return; //返回
r.state = BroadcastRecord.APP_RECEIVE;
String targetProcess = info.activityInfo.processName;
r.curComponent = component;
final int receiverUid = info.activityInfo.applicationInfo.uid;
// If it's a singleton, it needs to be the same app or a special app
if (r.callingUid != Process.SYSTEM_UID && isSingleton
&& mService.isValidSingletonCall(r.callingUid, receiverUid))
info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);
r.curReceiver = info.activityInfo;
// Broadcast is being executed, its package can't be stopped.
try
AppGlobals.getPackageManager().setPackageStoppedState(
r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid));
catch (RemoteException e)
catch (IllegalArgumentException e)
...
// Is this receiver's application already running?
ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
info.activityInfo.applicationInfo.uid, false);
//如果接收者所在进程已经存在,则调用processCurBroadcastLocked发送该广播。
if (app != null && app.thread != null)
try
app.addPackage(info.activityInfo.packageName,
info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
processCurBroadcastLocked(r, app); //该函数会通过binder机制调用接收者的scheduleReceiver方法
return; //已发送,因此退出,等待处理结果
...
//如果不存在,则需要先启动该进程
if(r.curApp=mService.startProcessLocked(targetProcess, info.activityInfo.applicationInfo, true,
r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, "broadcast", r.curComponent,
(r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false)) == null)
//如果启动失败:
logBroadcastReceiverDiscardLocked(r); //记录log
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false); //结束该广播接收器
scheduleBroadcastsLocked(); //进入下一次广播发送调度
r.state = BroadcastRecord.IDLE;
return;
//启动进程是异步的,很耗时,所以将该BraodcastRecord放入mPendingBroadcast存起来
//等到下次进入processNextBroadcast时处理。
mPendingBroadcast = r;
mPendingBroadcastRecvIndex = recIdx;
从上面的代码可知:
- 对于动态注册的接收者,最终调用deliverToRegisteredReceiverLocked方法发送广播,该方法代码如下:
private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered)
boolean skip = false;
...//各种权限检查,如果不符合,设置skip = true
if (!skip)
if (ordered)
... //对于有序广播,做了若干预处理
try
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
...
catch (RemoteException e)
...
可见,进一步调用了performReceiveLocked方法,代码如下:
private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, int sendingUser) throws RemoteException
if (app != null)
if (app.thread != null)
// 如果广播接收者所在进程存在,则通过binder机制调用该进程的scheduleRegisteredReceiver方法
// 该方法内部会进一步调用receiver.performReceive方法
// 注意:该Binder调用时one-way的。即AMS将binder请求发送给binder-driver就返回。!!
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.repProcState);
else
...
else
//否则,直接调用接收者的performReceive方法
receiver.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser);
- 对于静态注册的接收者,最终调用processCurBroadcastLocked方法发送广播,该方法代码如下:
private final void processCurBroadcastLocked(BroadcastRecord r,
ProcessRecord app) throws RemoteException
...
try
mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
//调用接收者进程的scheduleReceiver方法。
app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
app.repProcState);
started = true;
finally
...
到这里,processNextBroadcast整个调度流程就结束了。但有个问题,还需要解决。
刚才讲到,对于静态注册的接受者,如果应用进程还没有启动,需要先调用startProcessLocked()启动进程。
问题来了,应用程序启动后,怎么知道有个广播需要处理呢?
我们知道,应用进程启动后,会通过binder机制调用AMS的attachApplication方法,该方法进一步调用attachApplicationLocked方法。
在attachApplicationLocked方法中,有以下代码段:
// Check if a next-broadcast receiver is in this process...
if (!badApp && isPendingBroadcastProcessLocked(pid))
try
didSomething |= sendPendingBroadcastsLocked(app);
catch (Exception e)
...
其中,isPendingBroadcastProcessLocked()代码如下:
public boolean isPendingBroadcastProcessLocked(int pid)
return mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid;
检查mPendingBroadcastpid.curApp.pid是否等于本进程的pid。如果等于,就代表mPendingBroadcast中暂存的BroadcastRecord就是等待本进程启动后进行处理的。
处理广播的函数当然就是sendPendingBroadcastsLocked:
public boolean sendPendingBroadcastsLocked(ProcessRecord app)
...
final BroadcastRecord br = mPendingBroadcast;
if (br != null && br.curApp.pid == app.pid)
try
mPendingBroadcast = null;
processCurBroadcastLocked(br, app);
...
catch (Exception e)
...
return didSomething;
首先,将mPendingBroadcast设置为null,然后就调用processCurBroadcastLocked()处理该广播,processCurBroadcastLocked的处理过程上面已经讲了。
现在,我们再看processNextBroadcast()刚开始时候的一段代码就容易理解了,代码如下:
//mPendingBroadcast != null说明等待启动的那个应用还没有处理该广播,因为如果处理,会将它设为null
if (mPendingBroadcast != null)
boolean isDead;
synchronized (mService.mPidsSelfLocked)
ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);
isDead = proc == null || proc.crashing;
if (!isDead)
// 进程已经起来了,但还没有来得及处理该广播,所以上是关于[Android5.1]Broadcast机制的主要内容,如果未能解决你的问题,请参考以下文章
Android学习笔记-Broadcast01-详解广播机制
Android学习笔记-Broadcast01-详解广播机制
Android学习笔记-Broadcast01-详解广播机制
Android Broadcast Receiver (广播接收者)