动态广播的注册和收发原理
广播的注册原理
- 注册广播一般通过 Context 的 registerReceiver() 方法,通过一些列的简单调用 ,调用到了 registerReceiverInternal() 方法。
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
IIntentReceiver rd = null;
if (receiver != null) {
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
final Intent intent = ActivityManager.getService().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
broadcastPermission, userId, flags);
return intent;
}
registerReceiverInternal() 中,先创建了 binder 对象 IIntentReceiver ,然后通过 AMS 调用 registerReceiver() 来注册广播,下面看看是如何创建 IIntentReceiver 的。
public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
Context context, Handler handler,
Instrumentation instrumentation, boolean registered) {
synchronized (mReceivers) {
LoadedApk.ReceiverDispatcher rd = null;
ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
if (registered) {
map = mReceivers.get(context);
if (map != null) {
rd = map.get(r);
}
}
if (rd == null) {
rd = new ReceiverDispatcher(r, context, handler,
instrumentation, registered);
if (registered) {
if (map == null) {
map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
mReceivers.put(context, map);
}
map.put(r, rd);
}
} else {
rd.validate(context, handler);
}
rd.mForgotten = false;
return rd.getIIntentReceiver();
}
}
getReceiverDispatcher() 中,通过 BroadcastReceiver 对象 和 Content 对象 创建了IIntentReceiver 对象,并存入到 Map 中,下次如果再获取直接从 Map 中返回。所以这里可以确定 一个 Content 和 BroadcastReceiver 同时来确定一个 IIntentReceiver 对象,也就是同一个Content对应不同的 BroadcastReceiver 会生成不同的 IIntentReceiver ,反之也一样。这和之前讲过 Service 的差不多。下面是 ReceiverDispatcher 的构造函数
- ReceiverDispatcher 其构造函数引用了 BroadcastReceiver 对象的引用 ,同时还 new 了 InnerReceiver 对象。
ReceiverDispatcher(BroadcastReceiver receiver, Context context,
Handler activityThread, Instrumentation instrumentation,
boolean registered) {
if (activityThread == null) {
throw new NullPointerException("Handler must not be null");
}
mIIntentReceiver = new InnerReceiver(this, !registered);
mReceiver = receiver;
mContext = context;
mActivityThread = activityThread;
mLocation.fillInStackTrace();
}
InnerReceiver 对象就是 binder 对象,他引用了 ReceiverDispatcher 对象,
final static class InnerReceiver extends IIntentReceiver.Stub {
final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
final LoadedApk.ReceiverDispatcher mStrongRef;
InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
mStrongRef = strong ? rd : null;
}
}
所以引用链如下: AMS -> IIntentReceiver -> ReceiverDispatcher -> BroadcastReceiver ;所以 AMS 可以通过这么一个引用调用到 BroadcastReceiver 的 onReceive() 函数。
- 那么注册广播在 AMS 是怎么处理的?上面说过 registerReceiverInternal() 方法创建了 ReceiverDispatcher 后调用了 AMS 的 registerReceiver() 函数,
public Intent registerReceiver(IApplicationThread caller, String callerPackage,IIntentReceiver receiver, IntentFilter filter,s) {
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
if (rl.app != null) {
final int totalReceiversForApp = rl.app.receivers.size();
rl.app.receivers.add(rl);
}
mRegisteredReceivers.put(receiver.asBinder(), rl);
}
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId, instantApp, visibleToInstantApps);
rl.add(bf);
mReceiverResolver.addFilter(bf);
}
广播的发送原理
广播的发送一般通过 public void sendBroadcast(Intent intent) 方法发送
@Override
public void sendBroadcast(Intent intent) {
ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
}
public final int broadcastIntent(IApplicationThread caller,Intent intent, ...) {
int res = broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, appOp, bOptions, serialized, sticky,
callingPid, callingUid, userId);
return res;
}
}
final int broadcastIntentLocked(ProcessRecord callerApp,String callerPackage, Intent intent, ...){
List<BroadcastFilter> registeredReceivers = null;
registeredReceivers = mReceiverResolver.queryIntent(intent,resolvedType, false , userId);
if (!ordered && NR > 0) {
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
resultCode, resultData, resultExtras, ordered, sticky, false, userId);
if (!replaced) {
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
registeredReceivers = null;
NR = 0;
}
}
- scheduleBroadcastsLocked()
public void scheduleBroadcastsLocked() {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
+ mQueueName + "]: current="
+ mBroadcastsScheduled);
if (mBroadcastsScheduled) {
return;
}
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
上面发送的 Handler 调用到了 processNextBroadcast(true); 方法 ,然后又调用了 processNextBroadcastLocked(fromMsg, false); fromMsg 为 true
- processNextBroadcastLocked(true, false);
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
BroadcastRecord r;
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(r, (BroadcastFilter)target, false, i);
}
}
}
performReceiveLocked() 到这就是广播的接收原理了
广播的接收原理
void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent, ) throws RemoteException {
if (app != null) {
if (app.thread != null) {
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.repProcState);
}
} else {
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
}
}
上面的方法:如果 app.thread != null 不为 null ,则调用了 app.thread.scheduleRegisteredReceiver 方法,而他也直接引用了 receiver 这个 binder 对象,只有当 app.thread == null 的时候才会这么调用。目的是为了让所有进程广播尽量的串行调用。scheduleRegisteredReceiver 内部也是调用的 receiver.performReceiv() 函数
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);
}
- IIntentReceiver 之前创建的时候他的实现类是 ReceiverDispatcher 的内部类 InnerReceiver 那么看一下它的 performReceive 方法。
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
final LoadedApk.ReceiverDispatcher rd;
if (intent == null) {
rd = null;
} else {
rd = mDispatcher.get();
}
if (rd != null) {
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);
} else {
IActivityManager mgr = ActivityManager.getService();
try {
if (extras != null) {
extras.setAllowFds(false);
}
mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
这个方法就是获取到 ReceiverDispatcher 对象后调用了 performReceive 方法
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) {
} else {
if (ActivityThread.DEBUG_BROADCAST) {
int seq = intent.getIntExtra("seq", -1);
}
}
if (intent == null || !mActivityThread.post(args.getRunnable())) {
}
}
performReceive 中,创建了 Args 对象,其内部有一个 runnable 对象,然后把它 post 到了 mActivityThread 中,所以广播执行的 runnable 方法是在主线程调用的。
public final Runnable getRunnable() {
return () -> {
final BroadcastReceiver receiver = mReceiver;
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
}
if (receiver.getPendingResult() != null) {
finish();
}
};
}
public final void finish() {
if (mType == TYPE_COMPONENT) {
final IActivityManager mgr = ActivityManager.getService();
if (QueuedWork.hasPendingWork()) {
QueuedWork.queue(new Runnable() {
@Override public void run() {
sendFinished(mgr);
}
}, false);
} else {
sendFinished(mgr);
}
} else if (mOrderedHint && mType != TYPE_UNREGISTERED) {
final IActivityManager mgr = ActivityManager.getService();
sendFinished(mgr);
}
}
小结
对于普通的动态广播,AMS 是并行分发的 ,但是到了客户端就会串行分发了

静态广播的注册和收发原理
广播的注册原理
- 和动态广播不一样,静态广播的注册是在 AndroidManifest.xml 中配置的。之前讲过,在 SystemServer 启动后执行的 run 方法中,启动了 PackageManagerService ,在 PMS 中解析了每个安装包的 AndroidManifest 文件,代码从创建 PMS 的构造函数为起点,调用到了 PackageParse.java 中的 parseBaseApplication() 函数,其中有下面的代码:
else if (tagName.equals("receiver")) {
Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
true, false);
owner.receivers.add(a);
}
通过 parseActivity() 函数,解析 xml 的数据,返回了 Activity 对象,这个 Activity 不是 UI 那个Activity,只是一个普通组件。解析完成后加入到 receivers 列表中,需要使用的时候到里面去查。
广播的分发原理
- context 的 sendBroadcast()
@Override
public void sendBroadcast(Intent intent) {
ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
}
sendBroadcast() 函数会调用到 AMS 的 broadcastIntent() 其内部又调用了 broadcastIntentLocked() 函数
final int broadcastIntentLocked(ProcessRecord callerApp,...{
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
List<BroadcastFilter> registeredReceiversForUser =
mReceiverResolver.queryIntent(intent,
resolvedType, false , users[i]);
if (registeredReceivers == null) {
registeredReceivers = registeredReceiversForUser;
} else if (registeredReceiversForUser != null) {
registeredReceivers.addAll(registeredReceiversForUser);
}
if (!ordered && NR > 0) {
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
resultCode, resultData, resultExtras, ordered, sticky, false, userId);
final boolean replaced = replacePending
&& (queue.replaceParallelBroadcastLocked(r) != null);
if (!replaced) {
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
registeredReceivers = null;
NR = 0;
}
if ((receivers != null && receivers.size() > 0){
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,)
queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
return ActivityManager.BROADCAST_SUCCESS;
}
queue.scheduleBroadcastsLocked(); 分发广播和动态广播那一养走到了 processNextBroadcastLocked() 函数,但是函数内部处理静态广播比较复杂,因为它是串行的,要等待各种事件的返回才能开始下一个广播的发送。
先处理并行分发的广播(上面已经讲过)
如果有 pending广播,就直接返回,等待应用进程启动
如果广播分发超时,废弃这个广播,处理下一个
如果没有超时,正在分发中,则先返回等待
如果当前广播分发完了一个receiver,进行下一个
如果是动态注册的,直接分发(动态注册说明进程已经启动了)
如果是静态注册的,先看进程是否启动了
如果进程启动了直接分发,如果未启动则线启动进程,将广播设置成 pending 状态
进程启动后 attachApplication 的时候处理这个 pending 广播
- processNextBroadcastLocked
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
BroadcastRecord r;
while (mParallelBroadcasts.size() > 0) {
}
do {
if (mOrderedBroadcasts.size() == 0) {
return;
}
r = mOrderedBroadcasts.get(0);
long now = SystemClock.uptimeMillis();
if ((numReceivers > 0) && (now > r.dispatchTime + (2 * mTimeoutPeriod * numReceivers))) {
broadcastTimeoutLocked(false);
forceReceive = true;
r.state = BroadcastRecord.IDLE;
}
if (r.state != BroadcastRecord.IDLE) {
return;
}
if (r.receivers == null || r.nextReceiver >= numReceivers || r.resultAbort || forceReceive) {
cancelBroadcastTimeoutLocked();
mOrderedBroadcasts.remove(0);
r = null;
looped = true;
continue;
}
}
}
broadcastTimeoutLocked() 是如何处理超时的
final void broadcastTimeoutLocked(boolean fromMsg) {
BroadcastRecord r = mOrderedBroadcasts.get(0);
Object curReceiver;
if (r.nextReceiver > 0) {
curReceiver = r.receivers.get(r.nextReceiver-1);
r.delivery[r.nextReceiver-1] = BroadcastRecord.DELIVERY_TIMEOUT;
} else {
curReceiver = r.curReceiver;
}
if (mPendingBroadcast == r) {
mPendingBroadcast = null;
}
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
mHandler.post(new AppNotResponding(app, anrMessage));
}
- 超时过后会继续下一步 看 processNextBroadcastLocked 方法下一步
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
int recIdx = r.nextReceiver++;
r.receiverTime = SystemClock.uptimeMillis();
if (recIdx == 0) {
r.dispatchTime = r.receiverTime;
r.dispatchClockTime = System.currentTimeMillis();
}
if (!mPendingBroadcastTimeoutMessage) {
long timeoutTime = r.receiverTime + mTimeoutPeriod;
setBroadcastTimeoutLocked(timeoutTime);
}
final Object nextReceiver = r.receivers.get(recIdx);
if (nextReceiver instanceof BroadcastFilter) {
BroadcastFilter filter = (BroadcastFilter) nextReceiver;
deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
return;
}
ProcessRecord app = mService.getProcessRecordLocked(targetProcess, info.activityInfo.applicationInfo.uid, false);
r.state = BroadcastRecord.APP_RECEIVE;
if (app != null && app.thread != null && !app.killed) {
processCurBroadcastLocked(r, app, skipOomAdj);
return;
}
if ((r.curApp = mService.startProcessLocked(targetProcess, ) {
return;
}
mPendingBroadcast = r;
mPendingBroadcastRecvIndex = recIdx;
}
广播的接收原理
- 广播的发送那块将了 deliverToRegisteredReceiverLocked() 是分发动态 receiver 的函数,看看发送过后是怎么接收的
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered, int index) {
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
if (ordered) {
r.state = BroadcastRecord.CALL_DONE_RECEIVE;
}
}
void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,...) throws RemoteException {
if (app != null) {
if (app.thread != null) {
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.repProcState);
}
}
}
- app.thread.scheduleRegisteredReceiver()
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);
}
receiver 是 IIntentReceiver ,之前讲过 发送广播时,因为 ReceiverDispatcher 不能直接 IPC 传输,所以 通过 ReceiverDispatcher类的内部类InnerReceiver 封装成了binder 对象。所以 receiver.performReceive 调用到的是InnerReceiver 的 performReceive 方法,因为 InnerReceiver 引用了 ReceiverDispatcher ,performReceive 调用到ReceiverDispatcher 的 performReceive 方法。
- ReceiverDispatcher 的 performReceive 方法。
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 || !mActivityThread.post(args.getRunnable())) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManager.getService();
args.sendFinished(mgr);
}
}
}
执行了 mActivityThread.post(args.getRunnable()) ,看看 runnable 执行内容
public final Runnable getRunnable() {
return () -> {
final BroadcastReceiver receiver = mReceiver;
final boolean ordered = mOrdered;
final IActivityManager mgr = ActivityManager.getService();
final Intent intent = mCurIntent;
mCurIntent = null;
mDispatched = true;
mPreviousRunStacktrace = new Throwable("Previous stacktrace");
if (receiver == null || intent == null || mForgotten) {
if (mRegistered && ordered) {
sendFinished(mgr);
}
return;
}
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
}
if (receiver.getPendingResult() != null) {
finish();
}
};
}
}
Runnable 中主要执行了 onReceive 回调,然后通知 AMS 当前分发完成, AMS 可以继续分发下一个了,调用 AMS 的 am.finishReceiver() 方法
public void finishReceiver(IBinder who, int resultCode, String resultData,
Bundle resultExtras, boolean resultAbort, int flags) {
final long origId = Binder.clearCallingIdentity();
try {
boolean doNext = false;
BroadcastRecord r;
synchronized(this) {
BroadcastQueue queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
? mFgBroadcastQueue : mBgBroadcastQueue;
r = queue.getMatchingOrderedReceiver(who);
if (r != null) {
doNext = r.queue.finishReceiverLocked(r, resultCode,
resultData, resultExtras, resultAbort, true);
}
if (doNext) {
r.queue.processNextBroadcastLocked( false, true);
}
}
}
}
|