Android广播机制——广播的发送
来源:互联网 发布:项目经验怎么写 知乎 编辑:程序博客网 时间:2024/05/02 05:13
基于Android 7.0源码,分析Android广播机制的发送过程。
一、概述
按照广播的类型,可以分为普通广播、有序广播和sticky广播。在注册广播的时候,可以设置优先级,在发送order广播的时候,广播注册者根据优先级顺序依次接受intent,但是发送普通广播的时候,会忽略广播接收者的优先级,并将广播发送给所有符合条件的广播接收者处理。
- 普通广播:
所有匹配的接收器都会接收到此广播;
- 有序广播:
根据广播接收器的IntentFilter的priority属性值的大小一次调用,并可以通过调用abortBroadcast()阻止广播继续向下传播;
- sticky广播:
可以在接收器注册之前发出的广播,sticky广播在发送后就一直存在于系统的消息容器里面,等待对应的接收器去处理,如果暂时没有接收器处理这个消息则一直在消息容器里面处于等待状态。
从ContextImpl.java文件中,Android 7.0提供了如下发送广播的接口:
- public void sendBroadcast(Intent intent)
- public void sendBroadcast(Intent intent, int userId)
- public void sendBroadcast(Intent intent, String receiverPermission)
- 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 sendStickyBroadcast(Intent intent)
- public void sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
sendBroadcast是最简单发送广播的接口。
sendOrderedBroadcast是用来向系统发出有序广播,有序广播对应的所有接收器只能按照一定的优先级顺序依次接收intent,优先级可以记录在AndroidManifest.xml文件中的元素的android:priority属性中,其数值越大表示优先级越高,取值范围为-1000到1000;也可以调用IntentFilter对象的setPriority()方法来设置优先级。
对于有序广播而言,前面的接收者可以对接收到的广播intent进行处理,并将处理结果放置到广播intent中,然后传递给下一个接收者,并且前面的接收者有权调用BroadcastReceiver.abortBroadcast终止该广播的进一步继续传播。
粘性广播可以保证在广播发送时尚未注册的receiver,一旦后面注册时,就能够马上接到之前发送过的sticky广播。
下面就来说说具体广播发送的流程。
二、广播发送流程
我们以在activity中发送最简单的普通广播为例,在发送方,一般会类似如下代码来发送广播:
Intent intent = new Intent();intent.setAction("com.android.xxxxx");//intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);//前台广播(默认是后台广播)sendBroadcast(intent);
在activity中直接调用sendBroadcast,实际调用的是ContextImpl.java中的同名同参的sendBroadcast接口。
1. ContextImpl.sendBroadcast
[===>frameworks\base\core\java\android\app\ContextImpl.java]
@Overridepublic void sendBroadcast(Intent intent) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(); 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 new RuntimeException("Failure from system", e); }}
这样就直接调用到了ActivityManagerService端broadcastIntent那去了。
2. ActivityManagerService.broadcastIntent
[===>frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java]
public final int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle options, 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(); int res = broadcastIntentLocked(callerApp, callerApp != null ? callerApp.info.packageName : null, intent, resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions, appOp, null, serialized, sticky, callingPid, callingUid, userId); Binder.restoreCallingIdentity(origId); return res; }}
直接来看broadcastIntentLocked,该函数的代码比较长,按照具体功能来说,具体的处理大概有以下几点:
- 1、给intent默认添加FLAG_EXCLUDE_STOPPED_PACKAGES标记;
- 2、处理与package等其他系统广播,判断是否有权限发送广播;
- 3、若发送的是粘性广播,需要更新系统的粘性广播列表;
- 4、获取与intent匹配的静态receiver列表receivers;
- 5、获取与intent匹配的动态receiver列表registeredReceivers;
- 6、向并行receiver发送广播;
- 7、将剩下的并行receiver按照优先级合并到静态receiver列表receivers中,此时作为串行receiver列表;
- 8、依次向串行receivers发送广播;
3. ActivityManagerService.broadcastIntentLocked
[===>frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java]
3.1 给intent添加FLAG_EXCLUDE_STOPPED_PACKAGES标记
// By default broadcasts do not go to stopped apps.intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
在3.1之后,系统的PakcageManagerService增加了对处于“stopped state”应用的管理,这个stopped和Activity生命周期中的stop状态是完全两码事,指的是安装后从来没有启动过或者被用户手动强制停止的应用。
注意到系统增加了2个Flag:FLAG_INCLUDE_STOPPED_PACKAGES和FLAG_EXCLUDE_STOPPED_PACKAGES ,来标识一个intent是否激活处于“stopped state”的应用。
/** * If set, this intent will not match any components in packages that * are currently stopped. If this is not set, then the default behavior * is to include such applications in the result. */public static final int FLAG_EXCLUDE_STOPPED_PACKAGES = 0x00000010;/** * If set, this intent will always match any components in packages that * are currently stopped. This is the default behavior when * {@link #FLAG_EXCLUDE_STOPPED_PACKAGES} is not set. If both of these * flags are set, this one wins (it allows overriding of exclude for * places where the framework may automatically set the exclude flag). */public static final int FLAG_INCLUDE_STOPPED_PACKAGES = 0x00000020;
从上面注释可以知道,如果intent同时设置了FLAG_EXCLUDE_STOPPED_PACKAGES和FLAG_INCLUDE_STOPPED_PACKAGES标记的话,它会覆盖掉FLAG_EXCLUDE_STOPPED_PACKAGES标记。具体的代码,介绍后面获取与intent匹配的receiver列表会贴出代码。
注意,FLAG_INCLUDE_STOPPED_PACKAGES标记只对开发者自定义的广播有效,对于系统广播是无效的。
3.2 处理与package等其他系统广播,判断是否有权限发送广播
这部分代码略过去了。
3.3 若发送的是粘性广播,需要更新系统的粘性广播列表
if (sticky) { if (checkPermission(android.Manifest.permission.BROADCAST_STICKY, callingPid, callingUid) != PackageManager.PERMISSION_GRANTED) {//检查是否申请了发送粘性广播权限BROADCAST_STICKY ... } if (userId != UserHandle.USER_ALL) { ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get( UserHandle.USER_ALL); if (stickies != null) { ArrayList<Intent> list = stickies.get(intent.getAction()); if (list != null) { int N = list.size(); int i; for (i=0; i<N; i++) { if (intent.filterEquals(list.get(i))) { ... } } } } } ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId); if (stickies == null) { stickies = new ArrayMap<>(); mStickyBroadcasts.put(userId, stickies); } ArrayList<Intent> list = stickies.get(intent.getAction()); if (list == null) { list = new ArrayList<>(); stickies.put(intent.getAction(), list); } final int stickiesCount = list.size(); int i; for (i = 0; i < stickiesCount; i++) { if (intent.filterEquals(list.get(i))) {//比较 // This sticky already exists, replace it. list.set(i, new Intent(intent)); break; } } if (i >= stickiesCount) { list.add(new Intent(intent)); }}
如果发送方调用的是sendStickyBroadcast时,此处的sticky变量为true。此时要记录发送的intent,就会更新mStickyBroadcasts表。mStickyBroadcasts的定义如下:
/** * State of all active sticky broadcasts per user. Keys are the action of the * sticky Intent, values are an ArrayList of all broadcasted intents with * that action (which should usually be one). The SparseArray is keyed * by the user ID the sticky is for, and can include UserHandle.USER_ALL * for stickies that are sent to all users. */final SparseArray<ArrayMap<String, ArrayList<Intent>>> mStickyBroadcasts = new SparseArray<ArrayMap<String, ArrayList<Intent>>>();
上面代码判断mStickyBroadcasts中是否存在相同的粘性广播,判断的过程是由Intent.filterEquals来执行,只会判断intent的action、data、type、package、component和categories信息。如果两个intent的data是不一样的,那么就会在ArrayList中为正在发送的粘性广播新增一项;如果两个intent的action、data、type、package、component和categories信息都相同,就会用新的(正在发送的)粘性广播intent替换掉旧的。
从上篇文章《Android广播机制——广播的注册》的动态注册小节中知道,每次动态注册receiver时,都会遍历一下mStickyBroadcast表,查看哪些intent可以和新receiver的intentfilter匹配,只有匹配的intent才会递送给新注册的动态receiver。
这里在用张图来说明动态注册时有关粘性广播的处理。
相亲对象——新注册的动态receiver的filter对action1和action4感兴趣,遍历时只会考虑action1和action4对应的子表ArrayList,并且两个子表可能只有一部分符合filter的择偶要求,最后才能和receiver相亲成功。
粘性广播和普通广播的发送过程除了更新mStickyBroadcasts表的动作外,没有什么其他的代码差异了。
继续接着看。
3.4 获取与intent匹配的静态receiver列表receivers
List receivers = null;if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);}
private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType, int callingUid, int[] users) { List<ResolveInfo> receivers = null; try { HashSet<ComponentName> singleUserReceivers = null; boolean scannedFirstReceivers = false; for (int user : users) { List<ResolveInfo> newReceivers = AppGlobals.getPackageManager() .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user); if (receivers == null) { receivers = newReceivers; } else if (newReceivers != null) { } } } catch (RemoteException ex) { // pm is in same process, this will never happen. } return receivers;}
使用包管理器的queryIntentReceivers()接口,查询出和intent匹配的所有静态receivers,此时所返回的查询结果本身已经排好序了,该返回值被直接赋值给了receivers变量。
3.5 获取与intent匹配的动态receiver列表registeredReceivers
registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false, userId);
从上篇文章《Android广播机制——广播的注册》的动态注册小节中知道,每次动态注册receiver时,都会创建对应BroadcastFilter,并将将注册的BroadcastFilter加入到mReceiverResolver中。
因此,这里只要直接通过intent就可以获取到对intent感兴趣的动态receiver列表registeredReceivers。
这里提一下,在获取动态注册receiver列表的过程中,会调用Intent.isExcludingStopped接口对intent是否被设置了FLAG_EXCLUDE_STOPPED_PACKAGES或者FLAG_INCLUDE_STOPPED_PACKAGES标记进行判断,依据下面代码可知,FLAG_INCLUDE_STOPPED_PACKAGES标记确实是可以覆盖FLAG_EXCLUDE_STOPPED_PACKAGES标记的。
mReceiverResolver.queryIntent(intent, resolvedType, false, userId) buildResolveList(intent, categories, debug, defaultOnly, resolvedType, scheme, firstTypeCut, finalList, userId); intent.isExcludingStopped()public class Intent implements Parcelable, Cloneable { ... public boolean isExcludingStopped() { return (mFlags&(FLAG_EXCLUDE_STOPPED_PACKAGES|FLAG_INCLUDE_STOPPED_PACKAGES)) == FLAG_EXCLUDE_STOPPED_PACKAGES; } ...}
3.6 向并行receiver发送广播
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. final BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callingPid, callingUid, resolvedType, requiredPermissions, 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) { queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } registeredReceivers = null; NR = 0;}
registeredReceivers列表存放的是动态注册的receiver,如果目前发送的是无序广播,那就会以并行的形式发送,并且将此时的registeredReceivers清空;如果目前发送的是有序广播,那就会以串行的形式发送,registeredReceivers列表就会放在下一步中合并到receivers列表后作为串行列表。
首先将依据intent新创建的BroadcastRecord节点入列BroadcastQueue的mParallelBroadcasts中,然后进行并行广播发送。并行广播的发送时,是发送完上一个,紧接着就发下一个,不会做任何的等待操作。至于发送的过程放到后面串行广播发送时再说。
Android系统关于广播有两个广播队列——前台广播队列mFgBroadcastQueue和后台广播队列mBgBroadcastQueue。在发送方发送广播时,默认是放置在后台广播队列的。但是发送方在给intent设置FLAG_RECEIVER_FOREGROUND标记后,发送的广播就会被放置在前台广播队列。
3.7 将剩下的并行receiver按照优先级合并到静态receiver列表receivers中,此时作为串行receiver列表
这里代码挺简单的就不贴出来了,只要知道会过滤一些特定的系统广播,并且会按照receiver的优先级来排序,合并到串行receivers列表中。
3.8 依次向串行receivers发送广播
if ((receivers != null && receivers.size() > 0) || resultTo != null) { BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callingPid, callingUid, resolvedType, requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId); if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r + ": prev had " + queue.mOrderedBroadcasts.size()); if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST, "Enqueueing broadcast " + r.intent.getAction()); boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r); if (!replaced) { queue.enqueueOrderedBroadcastLocked(r); queue.scheduleBroadcastsLocked(); }} else { // There was nobody interested in the broadcast, but we still want to record // that it happened. if (intent.getComponent() == null && intent.getPackage() == null && (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { // This was an implicit broadcast... let's record it for posterity. addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0); }}
和3.6小节类似,首先将依据intent新创建的BroadcastRecord节点入列BroadcastQueue的mOrderedBroadcasts中,然后进行串行广播发送。
串行广播和并行广播发送时都是使用的BroadcastQueue.scheduleBroadcastsLocked,最终会间接的使用BroadcastQueue.processNextBroadcast(),由于这段过程比较复杂,单独拿出来做一节的分析。
4. BroadcastQueue.processNextBroadcast
[===>frameworks\base\services\core\java\com\android\server\am\BroadcastQueue.java]
流程比较长,根据具体的处理,大致可以分成四个部分:
- 1、发送并行广播;
- 2、发送当前有序广播;
- 3、获取并发送下一条有序广播;
4.1 发送并行广播
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); } addBroadcastToHistoryLocked(r);}
在之前第3.6小节,向并行receiver发送广播前会依据动态注册的receiver列表registeredReceivers和intent来创建BroadcastRecord节点,这样BroadcastRecord.receivers存储着对intent感兴趣的receiver列表。然后在这里发送前一个个遍历发送。
4.1.1 BroadcastQueue.deliverToRegisteredReceiverLocked
try { if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) { // Skip delivery if full backup in progress // If it's an ordered broadcast, we need to continue to the next receiver. if (ordered) { skipReceiverLocked(r); } } else { 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) { ...}
4.1.2 BroadcastQueue.performReceiveLocked
void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) throws RemoteException { // Send the intent to the receiver asynchronously using one-way binder calls. if (app != null) { if (app.thread != null) { // If we have an app thread, do the call through that so it is // correctly ordered with other one-way calls. try { app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode, data, extras, ordered, sticky, sendingUser, app.repProcState); } catch (RemoteException ex) { // Failed to call into the process. It's either dying or wedged. Kill it gently. } } else { // Application has died. Receiver doesn't exist. } } else { receiver.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser); }}
随后就转到了ActivityThread中去了。注意,这里的receiver对应的是
ReceiverDispatcher的Binder实体——InnerReceiver了。
4.1.3 ActivityThread.scheduleRegisteredReceiver
// This function exists to make sure all receiver dispatching is// correctly ordered, since these are one-way calls and the binder driver// applies transaction ordering per object for such calls.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);}
4.1.3 InnerReceiver.performReceive
4.1.4 ReceiverDispatcher.performReceive
[===>frameworks\base\core\java\android\app\LoadedApk.java]
static final class ReceiverDispatcher { ... final Handler mActivityThread; ... ReceiverDispatcher(BroadcastReceiver receiver, Context context, Handler activityThread, Instrumentation instrumentation, boolean registered) { ... mActivityThread = activityThread; ... } final static class InnerReceiver extends IIntentReceiver.Stub { @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) { Log.wtf(TAG, "Null intent received"); rd = null; } else { rd = mDispatcher.get(); } if (rd != null) { rd.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser);//调用ReceiverDispatcher.performReceive } else { ... } } } ... 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)) { if (mRegistered && ordered) { IActivityManager mgr = ActivityManagerNative.getDefault(); args.sendFinished(mgr); } } }}
在ReceiverDispatcher.performReceive中有创建Args对象,并且有调用mActivityThread.post(args),mActivityThread是之前注册广播接收器时指定的,若用户注册时未指定handler,则此时的mActivityThread就为应用进程的主线程,这里将新创建的Args给post到了mActivityThread这个Handler中,把消息放入MessageQueue,再调用Args的run()方法。
4.1.5 LoadedApk.Args.run
[===>frameworks\base\core\java\android\app\LoadedApk.java]
static final class ReceiverDispatcher { ... final class Args extends BroadcastReceiver.PendingResult implements Runnable { ... public void run() { final BroadcastReceiver receiver = mReceiver; ... Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg"); try { ClassLoader cl = mReceiver.getClass().getClassLoader();//获取mReceiver的类加载器 intent.setExtrasClassLoader(cl); intent.prepareToEnterProcess(); setExtrasClassLoader(cl); receiver.setPendingResult(this); receiver.onReceive(mContext, intent);//回调具体receiver的onReceive方法 } catch (Exception e) { ... } if (receiver.getPendingResult() != null) { finish(); } Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } } ...}
终于看到了很熟悉的onReceive函数,这里利用反射机制,创建出BroadcastRecord对象,随后回调该对象的onReceive。
这里最后调用了finish,由于Args继承BroadcastReceiver.PendingResult,PendingResult有finish,所以这里实际上调用的是BroadcastReceiver.PendingResult.finish。
4.1.6 BroadcastReceiver.PendingResult.finish
[===>frameworks\base\core\java\android\content\BroadcastReceiver.java]
public abstract class BroadcastReceiver { private PendingResult mPendingResult; public static class PendingResult { public final void finish() { if (mType == TYPE_COMPONENT) { final IActivityManager mgr = ActivityManagerNative.getDefault(); if (QueuedWork.hasPendingWork()) { QueuedWork.singleThreadExecutor().execute( new Runnable() { @Override public void run() { sendFinished(mgr); } }); } else { sendFinished(mgr); } } else if (mOrderedHint && mType != TYPE_UNREGISTERED) { final IActivityManager mgr = ActivityManagerNative.getDefault(); sendFinished(mgr); } } ... } public void sendFinished(IActivityManager am) { synchronized (this) { if (mFinished) { throw new IllegalStateException("Broadcast already finished"); } mFinished = true; try { if (mResultExtras != null) { mResultExtras.setAllowFds(false); } if (mOrderedHint) { am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras, mAbortBroadcast, mFlags); } else { am.finishReceiver(mToken, 0, null, null, false, mFlags); } } catch (RemoteException ex) { } } } ...}
上面无论如何都会最终调用到ActivityManagerService.finishReceiver。
4.1.7 ActivityManagerService.finishReceiver
[===>frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java]
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.processNextBroadcast(false); } trimApplications(); } finally { Binder.restoreCallingIdentity(origId); }}
4.2 发送当前有序广播
if (mPendingBroadcast != null) { boolean isDead; synchronized (mService.mPidsSelfLocked) { ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);//从mPidsSelfLocked获取正在处理该广播进程 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) { // No more broadcasts pending, so all done! mService.scheduleAppGcsLocked();//所有串行广播处理完成,则调度执行gc if (looped) { // If we had finished the last ordered broadcast, then // make sure all processes have correct oom and sched // adjustments. mService.updateOomAdjLocked(); } return; } r = mOrderedBroadcasts.get(0);//获取第一条串行广播 boolean forceReceive = false; // Ensure that even if something goes awry with the timeout // detection, we catch "hung" broadcasts here, discard them, // and continue to make progress. // // This is only done if the system is ready so that PRE_BOOT_COMPLETED // receivers don't get executed with timeouts. They're intended for // one time heavy lifting after system upgrades and can take // significant amounts of time. int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;//获取所接收该广播的接受者receiver个数 if (mService.mProcessesReady && r.dispatchTime > 0) { long now = SystemClock.uptimeMillis(); if ((numReceivers > 0) && (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {//广播处理超时,预定的超时时间为2*mTimeoutPeriod*numReceivers broadcastTimeoutLocked(false); // forcibly finish this broadcast forceReceive = true; r.state = BroadcastRecord.IDLE; } } if (r.state != BroadcastRecord.IDLE) { return; } if (r.receivers == null || r.nextReceiver >= numReceivers || r.resultAbort || forceReceive) {//无receiver接收;已发送给所有receiver;其中一个receiver调用了abortBroadcast;在时限内未发送给所有receiver // No more receivers for this broadcast! Send the final // result if requested... if (r.resultTo != null) { try { performReceiveLocked(r.callerApp, r.resultTo, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, false, false, r.userId);//处理广播,将会调用到BroadcastReceiver.onReceive // 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();//移除BROADCAST_TIMEOUT_MSG消息 // ... and on to the next... addBroadcastToHistoryLocked(r); if (r.intent.getComponent() == null && r.intent.getPackage() == null && (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { // This was an implicit broadcast... let's record it for posterity. mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage, r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime); } mOrderedBroadcasts.remove(0);//移除掉该BroadcastRecord节点(移除动作只有这一处) r = null; looped = true; continue; }} while (r == null);
在处理有序广播时,就要涉及到广播超时的问题了。
我们知道,系统中前台广播队列和后台广播队列。它们的时限要求有所不同。我们从代码中就可以知道,对于一个BroadcastRecord的超时时间是多少。
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); // forcibly finish this broadcast forceReceive = true; r.state = BroadcastRecord.IDLE; }}
对于前台广播队列,其mTimeoutPeriod为BROADCAST_FG_TIMEOUT = 10*1000ms = 10秒;对于后台广播队列,其mTimeoutPeriod为BROADCAST_BG_TIMEOUT = 60*1000ms = 60秒。
根据上面对于超时时限的计算。举个例子,如果“前台广播队列”的某个BroadcastRecord节点对应了3个receiver,那么在处理这个广播节点时,只要能在2x10x3=60秒内搞定就可以了,超过这个时限就会被认为发送该广播超时。
对于并行receiver而言,时限的作用小一点儿,因为动态receiver是直接递送到目标进程的,它不考虑目标端是什么时候处理完这个广播的。
4.3 获取并发送下一条有序广播
// Get the next receiver...int recIdx = r.nextReceiver++;//获取下一receiver的index索引值// Keep track of when this receiver started, and make sure there// is a timeout message pending to kill it if need be.r.receiverTime = SystemClock.uptimeMillis();if (recIdx == 0) {//处理对有序广播感兴趣的第一个receiver r.dispatchTime = r.receiverTime;//此时开始计时 r.dispatchClockTime = System.currentTimeMillis();}if (! mPendingBroadcastTimeoutMessage) { long timeoutTime = r.receiverTime + mTimeoutPeriod; setBroadcastTimeoutLocked(timeoutTime);}final BroadcastOptions brOptions = r.options;final Object nextReceiver = r.receivers.get(recIdx);if (nextReceiver instanceof BroadcastFilter) {//动态注册receiver // Simple case: this is a registered receiver who gets // a direct call. BroadcastFilter filter = (BroadcastFilter)nextReceiver; deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx); if (r.receiver == null || !r.ordered) { r.state = BroadcastRecord.IDLE; scheduleBroadcastsLocked(); } else { if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) { scheduleTempWhitelistLocked(filter.owningUid, brOptions.getTemporaryAppWhitelistDuration(), r); } } return;}// Hard case: need to instantiate the receiver, possibly// starting its application process to host it.ResolveInfo info = (ResolveInfo)nextReceiver;//静态注册的receiverComponentName component = new ComponentName( info.activityInfo.applicationInfo.packageName, info.activityInfo.name);// This is safe to do even if we are skipping the broadcast, and we need// this information now to evaluate whether it is going to be allowed to run.final int receiverUid = info.activityInfo.applicationInfo.uid;// If it's a singleton, it needs to be the same app or a special appif (r.callingUid != Process.SYSTEM_UID && isSingleton && mService.isValidSingletonCall(r.callingUid, receiverUid)) { info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);}String targetProcess = info.activityInfo.processName;ProcessRecord app = mService.getProcessRecordLocked(targetProcess, info.activityInfo.applicationInfo.uid, false);//获取当前静态注册receiver所在进程的ProcessRecord信息r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;r.state = BroadcastRecord.APP_RECEIVE;r.curComponent = component;r.curReceiver = info.activityInfo;if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) { scheduleTempWhitelistLocked(receiverUid, brOptions.getTemporaryAppWhitelistDuration(), r);}// 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?if (app != null && app.thread != null) {//若当前静态注册receiver所在进程存在 try { app.addPackage(info.activityInfo.packageName, info.activityInfo.applicationInfo.versionCode, mService.mProcessStats); processCurBroadcastLocked(r, app);//处理当前串行广播BroadcastRecord return; } catch (RemoteException e) { } catch (RuntimeException e) { logBroadcastReceiverDiscardLocked(r); finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false); scheduleBroadcastsLocked(); // We need to reset the state if we failed to start the receiver. r.state = BroadcastRecord.IDLE; return; } // If a dead object exception was thrown -- fall through to // restart the application.}// Not running -- get it started, to be executed when the app comes up.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); finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false); scheduleBroadcastsLocked(); r.state = BroadcastRecord.IDLE; return;}mPendingBroadcast = r;mPendingBroadcastRecvIndex = recIdx;
该部分的代码很长,就只分析没有任何异常发生,最简单的情况。
就某一条有序广播,对该广播感兴趣的receiver有可能是动态注册也有可能是静态注册。对于动态的receiver而言,其处理过程同4.1小节的过程大致相同,这里就不说了;对于静态注册的receiver而言,就需要分两种情况来处理,一种情况是receiver所在进程已经启动了,另外一种情况就是receiver所在进程未启动。
4.3.1 静态receiver所在进程已启动
if (app != null && app.thread != null) { try { app.addPackage(info.activityInfo.packageName, info.activityInfo.applicationInfo.versionCode, mService.mProcessStats); processCurBroadcastLocked(r, app); return; } catch (RemoteException e) { } catch (RuntimeException e) { } // If a dead object exception was thrown -- fall through to // restart the application.}
很简单,这里不需要启动进程,直接进入BroadcastQueue.processCurBroadcastLocked。
4.3.1.1 BroadcastQueue.processCurBroadcastLocked
private final void processCurBroadcastLocked(BroadcastRecord r, ProcessRecord app) throws RemoteException { r.receiver = app.thread.asBinder(); r.curApp = app; app.curReceiver = r; app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER); mService.updateLruProcessLocked(app, false, null); mService.updateOomAdjLocked(); // Tell the application to launch this receiver. r.intent.setComponent(r.curComponent); boolean started = false; try { mService.notifyPackageUse(r.intent.getComponent().getPackageName(), PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER); 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 { }
4.3.1.2 ActivityThread.scheduleReceiver
public final void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras, boolean sync, int sendingUser, int processState) { updateProcessState(processState, false); ReceiverData r = new ReceiverData(intent, resultCode, data, extras, sync, false, mAppThread.asBinder(), sendingUser); r.info = info; r.compatInfo = compatInfo; sendMessage(H.RECEIVER, r);}
注意,在发送有序广播给静态注册receiver时使用的是ReceiverData类,在发送有序广播给动态注册receiver时,使用的是ReceiverDispatcher类。
通过消息机制,在handleMessage中。
case RECEIVER: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp"); handleReceiver((ReceiverData)msg.obj); maybeSnapshot(); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break;
进入ActivityThread.handleReceiver。
4.3.1.3 ActivityThread.handleReceiver
private void handleReceiver(ReceiverData data) { ... IActivityManager mgr = ActivityManagerNative.getDefault(); BroadcastReceiver receiver; try { java.lang.ClassLoader cl = packageInfo.getClassLoader(); data.intent.setExtrasClassLoader(cl); data.intent.prepareToEnterProcess(); data.setExtrasClassLoader(cl); receiver = (BroadcastReceiver)cl.loadClass(component).newInstance(); } catch (Exception e) { } try { Application app = packageInfo.makeApplication(false, mInstrumentation); ContextImpl context = (ContextImpl)app.getBaseContext(); sCurrentBroadcastIntent.set(data.intent); receiver.setPendingResult(data); receiver.onReceive(context.getReceiverRestrictedContext(), data.intent); } catch (Exception e) { } finally { sCurrentBroadcastIntent.set(null); } if (receiver.getPendingResult() != null) { data.finish(); }}
这里后面的过程和4.1.6、4.1.7的过程大致相同,不过是ReceiverDispatcher换成了ReceiverData。会最终调用到ActivityManagerService.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.processNextBroadcast(false); } trimApplications(); } finally { Binder.restoreCallingIdentity(origId); }}
可以看到,如有必要,会继续调用BroadcastQueue.processNextBroadcast(),进入BroadcastQueue.processNextBroadcast()中4.2处理有序广播的地方时,是通过mOrderedBroadcasts.get(0)获取到的第一条有序广播,接着发送,从而完成有序广播的循环处理。
4.3.2 静态receiver所在进程未启动
对于进程未启动的情况,首要工作就是要将receiver所在进程启动起来。
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) { // Ah, this recipient is unavailable. Finish it if necessary, // and mark the broadcast record as ready for the next. Slog.w(TAG, "Unable to launch app " + info.activityInfo.applicationInfo.packageName + "/" + info.activityInfo.applicationInfo.uid + " for broadcast " + r.intent + ": process is bad"); logBroadcastReceiverDiscardLocked(r); finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false); scheduleBroadcastsLocked(); r.state = BroadcastRecord.IDLE; return;}mPendingBroadcast = r;mPendingBroadcastRecvIndex = recIdx;
由于进程启动比较耗时间,这里将正准备处理的有序广播保存在mPendingBroadcast中。在startProcessLocked过程中,正常情况下会执行到ActivityManagerService.attachApplicationLocked中。
if (!badApp && isPendingBroadcastProcessLocked(pid)) { try { didSomething |= sendPendingBroadcastsLocked(app); } catch (Exception e) { }}
boolean sendPendingBroadcastsLocked(ProcessRecord app) { boolean didSomething = false; for (BroadcastQueue queue : mBroadcastQueues) { didSomething |= queue.sendPendingBroadcastsLocked(app); } return didSomething;}
BroadcastQueue.sendPendingBroadcastsLocked
public boolean sendPendingBroadcastsLocked(ProcessRecord app) { boolean didSomething = false; final BroadcastRecord br = mPendingBroadcast; if (br != null && br.curApp.pid == app.pid) { try { mPendingBroadcast = null; processCurBroadcastLocked(br, app); didSomething = true; } catch (Exception e) { logBroadcastReceiverDiscardLocked(br); finishReceiverLocked(br, br.resultCode, br.resultData, br.resultExtras, br.resultAbort, false); scheduleBroadcastsLocked(); // We need to reset the state if we failed to start the receiver. br.state = BroadcastRecord.IDLE; throw new RuntimeException(e.getMessage()); } } return didSomething;}
这个时候就拿出在进程完全启动好之前保存在mPendingBroadcast的有序广播,进行处理。
aaaa
点击跳转
- Android广播机制——广播的发送
- Android之广播机制—自定义广播
- Android之广播机制—有序广播
- Android之广播机制—本地广播
- Android广播机制——广播的注册
- 【Android成长之路】全局大喇叭——广播机制的浅谈(发送自定义广播)
- Android的广播机制
- android的广播机制
- Android的广播机制
- Android的广播机制
- Android广播发送机制剖析【android广播系列二】
- Android广播机制---发送本地广播_android全局信息处理本地广播安全广播
- Android开发:广播机制:Broadcast——自定义广播方法
- Android 四大组件 —— 广播(广播机制解析)
- Android 四大组件 —— 广播(广播机制解析)
- Android中的广播机制(二)----- 发送广播
- 广播——Android应用程序发送广播(sendBroadcast)的过程分析
- Android——发送和接收广播
- VS2015 + Vmvare 调试驱动
- (c++)写两个函数,分别求两个整数的最大公约数和最小公倍数,用主函数调用这两个函数,并输出结果两个整数由键盘输入。
- 数据分析领域中最为人称道的七种降维方法
- nginx配置长连接---keepalive相关
- 2016迟到的总结
- Android广播机制——广播的发送
- 近日计划
- Android Studio上Vuforia AR引擎入门Demo
- android view滑动助手类 OverScroller VelocityTracker
- ssm 使用 DbUtils
- STM32模拟串口-ucosiii
- 如何抓取 带VLAN tag的包
- Backbone入门指南(六):View (视图)
- 23种设计模式(2):工厂方法模式