下图采用的品茗论道说广播悠然红茶的图片
https://my.oschina.net/youranhongcha/blog/226274
直观的解释了广播队列分发广播的流程
其实还是在ContextImpl中:
@Override public void sendBroadcast(Intent intent) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(this); //跳转到AMS中发送广播,广播表现形式就是intent ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false, getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
public final int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions, boolean serialized, boolean sticky, int userId) { enforceNotIsolatedCaller("broadcastIntent"); synchronized(this) { intent = verifyBroadcastLocked(intent); final ProcessRecord callerApp = getRecordForAppLocked(caller); final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); //在AMS中进行广播的分发 int res = broadcastIntentLocked(callerApp, callerApp != null ? callerApp.info.packageName : null, intent, resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions, serialized, sticky, callingPid, callingUid, userId); Binder.restoreCallingIdentity(origId); return res; } }
在AMS中broadcastIntentLocked, 首先完成这几件事情:
1.intent添加FLAG_EXCLUDE_STOPPED_PACKAGES标记
保证已停止app不会收到该广播
intent = new Intent(intent); intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
2.广播权限验证
isCallerSystem根据这个判断是不是系统,是系统可以发送任何广播,不是的话受限广播是不能发送的,没有权限的了
3.处理Package级别的广播
例如:
case Intent.ACTION_UID_REMOVED: case Intent.ACTION_PACKAGE_REMOVED: case Intent.ACTION_PACKAGE_CHANGED: case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE: case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE: case Intent.ACTION_PACKAGES_SUSPENDED: case Intent.ACTION_PACKAGES_UNSUSPENDED:
3.处理黏性广播列表mStickyBoradcast
同样在AMS中broadcastIntentLocked方法在完成以上的几个事件之后,就开始进行广播队列的分发:
// Figure out who all will receive this broadcast. List receivers = null; ListregisteredReceivers = null; // Need to resolve the intent to interested receivers... if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { //当前intent的所有静态注册广播接收者 receivers = collectReceiverComponents(intent, resolvedType, callingUid, users); } if (intent.getComponent() == null) { if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) { // Query one target user at a time, excluding shell-restricted users for (int i = 0; i < users.length; i++) { if (mUserController.hasUserRestriction( UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) { continue; } //当前的所有动态注册的广播接收者 List registeredReceiversForUser = mReceiverResolver.queryIntent(intent, resolvedType, false, users[i]); if (registeredReceivers == null) { registeredReceivers = registeredReceiversForUser; } else if (registeredReceiversForUser != null) { registeredReceivers.addAll(registeredReceiversForUser); } } } else { registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false, userId); } }
registeredReceivers 就记录了所有动态注册的广播接收者,接下来就处理动态广播:
final boolean replacePending = (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0; if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueing broadcast: " + intent.getAction() + " replacePending=" + replacePending); int NR = registeredReceivers != null ? registeredReceivers.size() : 0; if (!ordered && NR > 0) { // If we are not serializing this broadcast, then send the // registered receivers separately so they don't wait for the // components to be launched. //根据intent来返回广播队列,广播队列分为mFgBroadcastQueue 和mBgBroadcastQueue。 final BroadcastQueue queue = broadcastQueueForIntent(intent); //将intent包装起来,变成BroadcastRecord对象 BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callingPid, callingUid, resolvedType, requiredPermissions, //registeredReceivers这个属性比较重要,将动态注册的BroadcastReceiver传进去 appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId); if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r); final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r); if (!replaced) { //将BroadcastRecord插入到广播队列中mParallelBroadcasts,这里mParallelBroadcasts是处理并行广播的,就是sendBroadcast方法发送的广播 queue.enqueueParallelBroadcastLocked(r); //对广播进行处理,找到广播BroadcastRecord对象,对应的BroadcastFilter,然后在找ReceiverList,最后找到BroadcastReceiver,然后进行广播的处理 queue.scheduleBroadcastsLocked(); } registeredReceivers = null; NR = 0; }
队列分为mFgBroadcastQueue 和mBgBroadcastQueue,如下所示:
BroadcastQueue broadcastQueueForIntent(Intent intent) { final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0; if (DEBUG_BROADCAST_BACKGROUND) Slog.i(TAG_BROADCAST, "Broadcast intent " + intent + " on " + (isFg ? "foreground" : "background") + " queue"); return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue; }
每个队列mFgBroadcastQueue或者mBgBroadcastQueue,都有
final ArrayList mParallelBroadcasts = new ArrayList<>();
final ArrayList mOrderedBroadcasts = new ArrayList<>();
这两个属性分别处理并行和串行广播。
在队列里面进行广播的处理都是一条主线(不管串行和并行流程都是相似的):
queue.scheduleBroadcastsLocked(); mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this)) processNextBroadcast(true); deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false,app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.repProcState);
调到具体的注册广播的应用里面,然后在应用内进行处理。根据之前注册的IIntentReceiver进行对应的广播处理。
ActivityThread:
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent, int resultCode, String dataStr, Bundle extras, boolean ordered, boolean sticky, int sendingUser, int processState) throws RemoteException { updateProcessState(processState, false); receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky, sendingUser); }
LoadedApk.ReceiverDispatcher.InnerReceiver:
public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { final LoadedApk.ReceiverDispatcher rd; if (intent == null) { Log.wtf(TAG, "Null intent received"); rd = null; } else { rd = mDispatcher.get(); } if (rd != null) { //rd就是LoadedApk.ReceiverDispatcher,通过这个LoadedApk.ReceiverDispatcher,再进行performReceive rd.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser); } }
LoadedApk.ReceiverDispatcher:
public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { final Args args = new Args(intent, resultCode, data, extras, ordered, sticky, sendingUser); if (intent == null) { Log.wtf(TAG, "Null intent received"); } else { if (ActivityThread.DEBUG_BROADCAST) { int seq = intent.getIntExtra("seq", -1); Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq + " to " + mReceiver); } } //args是一个实现了Runnable的类,执行其中的run方法 if (intent == null || !mActivityThread.post(args)) { if (mRegistered && ordered) { IActivityManager mgr = ActivityManagerNative.getDefault(); if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, "Finishing sync broadcast to " + mReceiver); args.sendFinished(mgr); } } }
Args:
public void run() { final BroadcastReceiver receiver = mReceiver; try { ClassLoader cl = mReceiver.getClass().getClassLoader(); intent.setExtrasClassLoader(cl); intent.prepareToEnterProcess(); setExtrasClassLoader(cl); receiver.setPendingResult(this); //这个就是找到了对应的广播接受者,执行广播接受者的onReceive方法,其中的context是注册广播接受者注册时的context receiver.onReceive(mContext, intent); } }
注:1.并发广播先于有序广播,先进行并发广播的分发,然后再进行有序广播的分发;
2.有序广播有动态注册的广播,也有静态注册的广播。由于静态广播在AndroidManifest中配置,接受广播的时候
可能进程没有起来,所以要一个个启动进程(一下子启动大量进程可能系统无法做出反应吧)。