4.发送广播sendBroadcast
下图采用的品茗论道说广播悠然红茶的图片
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
5.主要广播分发的流程
同样在AMS中broadcastIntentLocked方法在完成以上的几个事件之后,就开始进行广播队列的分发:
// Figure out who all will receive this broadcast.
List receivers = null;
List<BroadcastFilter> registeredReceivers = 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<BroadcastFilter> 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,
i); - performReceiveLocked(…)
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中配置,接受广播的时候
可能进程没有起来,所以要一个个启动进程(一下子启动大量进程可能系统无法做出反应吧)。