原文地址:https://skytoby.github.io/2019/BroadcastCast%E5%B9%BF%E6%92%AD%E6%9C%BA%E5%88%B6%E5%8E%9F%E7%90%86/
一、概述
广播(BroadcastCast)用于进程/线程间的通信,广播有发送广播和接收广播两部分组成,其中广播接收者BroadcastReceiver是四大组件之一。
BroadcastReceiver分为两类:
-
静态广播:通过AndroidManifeset.xml的标签来注册BroadcastReceiver。
-
动态广播:通过AMS.registeredReceiver方式注册BroadcastReceiver,动态注册相对静态注册更加的灵活,在不需要时通过unregisteredReceiver来取消注册。
从广播的发送方式分为四种:
-
普通广播:完全异步的广播,在广播发出之后,所有的广播接收器几乎在同一时刻接收到这条广播消息,接收的先后顺序是随机的。通过Context.sendBroadcast发送。
-
有序广播:同步执行的广播。在广播发出去之后,同一时刻只有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑处理完成后,广播才可以继续传递。这种广播的接收顺序通过优先级(priority)设置,高的优先级先会收到广播。有序广播可以被接收者截断,使得后面的广播无法收到它。通过Context.sendOrderedBroadcast发送。
-
粘性广播:这种广播会一直滞留,当有匹配该广播的接收器被注册后,该接收器就会收到这个广播。粘性广播如果被销毁,下一次重建时会重新接收到消息数据。这种方式一般用来确保重要状态改变后的信息被持久的保存,并且能随时广播给新的广播接收器,比如:耗电量的改变。通过Context.sendStickyBroadcast发送。Android系统已经 @Deprecated该广播方式。
-
本地广播:发送处理的广播只能够在应用程序的内部进行传递,并且广播接收器也只能接收本应用程序发出的广播。通过LocalBroadcastManager.sendBroadcast发送。(基本原理是Handler,所以在AMS中没有本地广播的处理)
广播在系统中通过BroadcastRecord来记录。
/*** An active intent broadcast.*/
final class BroadcastRecord extends Binder {final Intent intent; // the original intent that generated usfinal ComponentName targetComp; // original component name set on the intentfinal ProcessRecord callerApp; // process that sent thisfinal String callerPackage; // who sent thisfinal int callingPid; // the pid of who sent thisfinal int callingUid; // the uid of who sent thisfinal boolean callerInstantApp; // caller is an Instant App?final boolean ordered; // serialize the send to receivers?final boolean sticky; // originated from existing sticky data?final boolean initialSticky; // initial broadcast from register to sticky?final int userId; // user id this broadcast was forfinal String resolvedType; // the resolved data typefinal String[] requiredPermissions; // permissions the caller has requiredfinal int appOp; // an app op that is associated with this broadcastfinal BroadcastOptions options; // BroadcastOptions supplied by caller//包括动态注册的BroadcastFilter和静态注册的ResolveInfofinal List receivers; // contains BroadcastFilter and ResolveInfo//广播的分发状态final int[] delivery; // delivery state of each receiverIIntentReceiver resultTo; // who receives final result if non-null//入队列时间long enqueueClockTime; // the clock time the broadcast was enqueued//分发时间long dispatchTime; // when dispatch started on this set of receivers//分发时间long dispatchClockTime; // the clock time the dispatch started//接收时间long receiverTime; // when current receiver started for timeouts.//广播完成时间long finishTime; // when we finished the broadcast.}
二、注册广播
注册广播一般可以在Activity/Service中调用registerReceiver方法,而这两者间接集成Context,其实现是ContextImpl。
2.1 CI.registerReceiver
[->ContextImpl.java]
@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {return registerReceiver(receiver, filter, null, null);}@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,String broadcastPermission, Handler scheduler) {return registerReceiverInternal(receiver, getUserId(),filter, broadcastPermission, scheduler, getOuterContext(), 0);}
其中broadcastPermission表示广播的权限,scheduler表示接收广播时onReceive执行的线程,当scheduler==null时代表在主线程中执行,大部分情况是不会指令scheduler。getOuterContext可以获取最外层调用者。
2.2 CI.registerReceiverInternal
[->ContextImpl.java]
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) {//主线程Handler赋予schedulerscheduler = mMainThread.getHandler();}//见2.3节,获取IIntentReceiverrd = mPackageInfo.getReceiverDispatcher(receiver, context, scheduler,mMainThread.getInstrumentation(), true);} else {if (scheduler == null) {scheduler = mMainThread.getHandler();}//context为空,新建ReceiverDispatcher对象(见2.3.1节),并获取IIntentReceiverrd = new LoadedApk.ReceiverDispatcher(receiver, context, scheduler, null, true).getIIntentReceiver();}}try {//通过Binder调用AMS.registerReceiverfinal Intent intent = ActivityManager.getService().registerReceiver(mMainThread.getApplicationThread(), mBasePackageName, rd, filter,broadcastPermission, userId, flags);if (intent != null) {intent.setExtrasClassLoader(getClassLoader());intent.prepareToEnterProcess();}return intent;} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}
2.3 LA.getReceiverDispatcher
[->LoadedApk.java]
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) {//广播分发者为空,创建ReceiverDispatcherrd = 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 {//验证广播分发者的context和handler是否一致rd.validate(context, handler);}rd.mForgotten = false;return rd.getIIntentReceiver();}}
mReceivers定义为final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers;
mReceivers是以Context为key,以ArrayMap为value的ArrayMap。
2.3.1 创建ReceiverDispatcher
[->LoadedApk.java]
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;mInstrumentation = instrumentation;mRegistered = registered;mLocation = new IntentReceiverLeaked(null);mLocation.fillInStackTrace();}
mActivityThread为前面传过来的Handler。
2.3.2 创建InnerReceiver
[->LoadedApk.java]
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;}...
}
InnerReceiver继承于IIntentReceiver.Stub,是一个服务器端,广播分发者通过getReceiverDispatcher可以获取该Binder服务端对象InnerReceiver,用于IPC通信。
2.4 AMS.registerReceiver
[->ActivityManagerService.java]
public Intent registerReceiver(IApplicationThread caller, String callerPackage,IIntentReceiver receiver, IntentFilter filter, String permission, int userId,int flags) {enforceNotIsolatedCaller("registerReceiver");ArrayList<Intent> stickyIntents = null;ProcessRecord callerApp = null;final boolean visibleToInstantApps= (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;int callingUid;int callingPid;boolean instantApp;synchronized(this) {if (caller != null) {//查询调用者的进程信息callerApp = getRecordForAppLocked(caller);if (callerApp == null) {throw new SecurityException("Unable to find app for caller " + caller+ " (pid=" + Binder.getCallingPid()+ ") when registering receiver " + receiver);}if (callerApp.info.uid != SYSTEM_UID &&!callerApp.pkgList.containsKey(callerPackage) &&!"android".equals(callerPackage)) {throw new SecurityException("Given caller package " + callerPackage+ " is not running in process " + callerApp);}callingUid = callerApp.info.uid;callingPid = callerApp.pid;} else {callerPackage = null;callingUid = Binder.getCallingUid();callingPid = Binder.getCallingPid();}//是否是即时应用instantApp = isInstantApp(callerApp, callerPackage, callingUid);userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,ALLOW_FULL_ONLY, "registerReceiver", callerPackage);//获取InterFilter中的ActionIterator<String> actions = filter.actionsIterator();if (actions == null) {ArrayList<String> noAction = new ArrayList<String>(1);noAction.add(null);actions = noAction.iterator();}// Collect stickies of usersint[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };while (actions.hasNext()) {String action = actions.next();for (int id : userIds) {//从mStickyBroadcasts中查看用户的sticky intentArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);if (stickies != null) {ArrayList<Intent> intents = stickies.get(action);if (intents != null) {if (stickyIntents == null) {stickyIntents = new ArrayList<Intent>();}//将sticky intent加入队列stickyIntents.addAll(intents);}}}}}ArrayList<Intent> allSticky = null;if (stickyIntents != null) {final ContentResolver resolver = mContext.getContentResolver();// Look for any matching sticky broadcasts...for (int i = 0, N = stickyIntents.size(); i < N; i++) {Intent intent = stickyIntents.get(i);//即时应用跳过// Don't provided intents that aren't available to instant apps.if (instantApp &&(intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {continue;}//查询匹配到的sticky广播,见2.4.2节// If intent has scheme "content", it will need to acccess// provider that needs to lock mProviderMap in ActivityThread// and also it may need to wait application response, so we// cannot lock ActivityManagerService here.if (filter.match(resolver, intent, true, TAG) >= 0) {if (allSticky == null) {allSticky = new ArrayList<Intent>();}//匹配成功,则将该intent添加到allSticky队列allSticky.add(intent);}}}//返回第一个stick intent// The first sticky in the list is returned directly back to the client.Intent sticky = allSticky != null ? allSticky.get(0) : null;if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Register receiver " + filter + ": " + sticky);if (receiver == null) {return sticky;}synchronized (this) {if (callerApp != null && (callerApp.thread == null|| callerApp.thread.asBinder() != caller.asBinder())) {// Original caller already died//调用者已经死亡return null;}ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());if (rl == null) {//对于没有注册的广播,则创建接收者队列rl = new ReceiverList(this, callerApp, callingPid, callingUid,userId, receiver);if (rl.app != null) {//每个应用最多只能注册1000个接收者final int totalReceiversForApp = rl.app.receivers.size();if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {throw new IllegalStateException("Too many receivers, total of "+ totalReceiversForApp + ", registered for pid: "+ rl.pid + ", callerPackage: " + callerPackage);}//新创建的接收者队列,添加到已注册队列rl.app.receivers.add(rl);} else {try {//服务停止后重连receiver.asBinder().linkToDeath(rl, 0);} catch (RemoteException e) {return sticky;}rl.linkedToDeath = true;}mRegisteredReceivers.put(receiver.asBinder(), rl);} else if (rl.uid != callingUid) {throw new IllegalArgumentException("Receiver requested to register for uid " + callingUid+ " was previously registered for uid " + rl.uid+ " callerPackage is " + callerPackage);} else if (rl.pid != callingPid) {throw new IllegalArgumentException("Receiver requested to register for pid " + callingPid+ " was previously registered for pid " + rl.pid+ " callerPackage is " + callerPackage);} else if (rl.userId != userId) {throw new IllegalArgumentException("Receiver requested to register for user " + userId+ " was previously registered for user " + rl.userId+ " callerPackage is " + callerPackage);}//创建BroadcastFilter队列,并添加到接收者队列BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,permission, callingUid, userId, instantApp, visibleToInstantApps);if (rl.containsFilter(filter)) {Slog.w(TAG, "Receiver with filter " + filter+ " already registered for pid " + rl.pid+ ", callerPackage is " + callerPackage);} else {rl.add(bf);if (!bf.debugCheck()) {Slog.w(TAG, "==> For Dynamic broadcast");}//新创建的广播过滤对象,添加到mReceiverResolver队列mReceiverResolver.addFilter(bf);}//所有匹配该filter的stick广播执行入队操作// Enqueue broadcasts for all existing stickies that match// this filter.if (allSticky != null) {ArrayList receivers = new ArrayList();receivers.add(bf);final int stickyCount = allSticky.size();for (int i = 0; i < stickyCount; i++) {Intent intent = allSticky.get(i);//根据intent返回前台或者后台广播队列,见2.4.3节BroadcastQueue queue = broadcastQueueForIntent(intent);BroadcastRecord r = new BroadcastRecord(queue, intent, null,null, -1, -1, false, null, null, OP_NONE, null, receivers,null, 0, null, null, false, true, true, -1);//该广播加入到并行队列queue.enqueueParallelBroadcastLocked(r);//调度广播,发送BROADCAST_INTENT_MSG消息,触发处理广播queue.scheduleBroadcastsLocked();}}return sticky;}}
mReceiverResolver记录着所有已经注册的广播,是以receiver IBinder为key, ReceiverList为value的ArrayMap。
在BroadcastQueue中有两个广播队列mParallelBroadcasts、mOrderedBroadcasts,类型为ArrayList
-
mParallelBroadcasts:并行广播队列,可以立刻执行,而无需等待另一个广播运行完成,该队列只允许动态已注册的广播,从而避免发生同时拉起大量进程来执行广播,前台和后台的广播分别位于独立的队列。
-
mOrderedBroadcasts:有序广播,同一时间只允许执行一个广播,该队列头部的广播就是活动广播,其他广播必须等待该广播结束才能运行,也是独立区别前台和后台的广播。
2.4.1 AMS.getRecordForAppLocked
[->ActivityManagerService.java]
ProcessRecord getRecordForAppLocked(IApplicationThread thread) {if (thread == null) {return null;}//从mLruProcesses队列中获取int appIndex = getLRURecordIndexForAppLocked(thread);if (appIndex >= 0) {return mLruProcesses.get(appIndex);}//mLruProcesses不存在,再检查一遍// Validation: if it isn't in the LRU list, it shouldn't exist, but let's// double-check that.final IBinder threadBinder = thread.asBinder();final ArrayMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap();for (int i = pmap.size()-1; i >= 0; i--) {final SparseArray<ProcessRecord> procs = pmap.valueAt(i);for (int j = procs.size()-1; j >= 0; j--) {final ProcessRecord proc = procs.valueAt(j);if (proc.thread != null && proc.thread.asBinder() == threadBinder) {Slog.wtf(TAG, "getRecordForApp: exists in name list but not in LRU list: "+ proc);return proc;}}}return null;}
mLruProcesses 定义为ArrayList mLruProcesses ,ProcessRecord对象中有一个IApplicationThread字段,根据该字段来查找对应的ProcessRecord。
2.4.3 IntentFilter.match
[->IntentFilter.java]
public final int match(ContentResolver resolver, Intent intent,boolean resolve, String logTag) {String type = resolve ? intent.resolveType(resolver) : intent.getType();return match(intent.getAction(), type, intent.getScheme(),intent.getData(), intent.getCategories(), logTag);}public final int match(String action, String type, String scheme,Uri data, Set<String> categories, String logTag) {//不存在匹配的action,存在即可以if (action != null && !matchAction(action)) {if (false) Log.v(logTag, "No matching action " + action + " for " + this);return NO_MATCH_ACTION;}//不存在匹配的type或dataint dataMatch = matchData(type, scheme, data);if (dataMatch < 0) {if (false) {if (dataMatch == NO_MATCH_TYPE) {Log.v(logTag, "No matching type " + type+ " for " + this);}if (dataMatch == NO_MATCH_DATA) {Log.v(logTag, "No matching scheme/path " + data+ " for " + this);}}return dataMatch;}//不存在匹配的category,需要全部匹配String categoryMismatch = matchCategories(categories);if (categoryMismatch != null) {if (false) {Log.v(logTag, "No matching category " + categoryMismatch + " for " + this);}return NO_MATCH_CATEGORY;}// It would be nice to treat container activities as more// important than ones that can be embedded, but this is not the way...if (false) {if (categories != null) {dataMatch -= mCategories.size() - categories.size();}}return dataMatch;}
该方法用于匹配Intent的数据是否成功,匹配的数据包括action,type,data,category四项,任何一项匹配不成功都会失败。
2.4.3 AMS.broadcastQueueForIntent
[->ActivityManagerService.java]
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;}
broadcastQueueForIntent通过判断intent中是否包含FLAG_RECEIVER_FOREGROUND来决定是前台广播还是后台广播
2.5 小结
注册广播:
1.注册广播的参数为广播BroadcastReceiver和过滤添加IntentFilter;
2.创建对象LoadedApk.ReceiverDispatcher.InnerReceiver,该对象集成于IIntentReceiver.Stub;
3.通过AMS把当前进程的ApplicationThread和InnerReceiver对象的代理类,注册到systemserver进程;
4.当广播receiver没有注册时,则创建广播接收者队列ReceiverList,该对象集成于ArrayList,并添加到AMS.mRegisteredReceivers(已注册广播队列);
5.创建BroadcastFilter队列,并添加到AMS.mReceiverResolver
6.将BroadcastFilter添加到广播接收者的ReceiverList
当注册的广播为Sticky广播:
1.创建BroadcastRecord,并添加到BroadcastQueue中的mParallelBroadcasts,注册后,调用AMS处理该广播
2.根据注册的intent中是否包含FLAG_RECEIVER_FOREGROUND,包含则是mFgBroadcastQueue队列,否则为mBgBroadcastQueue队列。
三、发送广播
和注册广播一样,最后调用的是ContextImpl.sendBroadcast
3.1 CI.sendBroadcast
[->ContextImpl.java]
@Overridepublic void sendBroadcast(Intent intent) {//UID如果是SYSTEM_UID则提示警告信息//"Calling a method in the system process without a qualified user:""warnIfCallingFromSystemProcess();String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());try {intent.prepareToLeaveProcess(this);//通过binder方式调用AMS.broadcastIntentActivityManager.getService().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();}}
3.2 AMS.broadcastIntent
[->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 bOptions,boolean serialized, boolean sticky, int userId) {enforceNotIsolatedCaller("broadcastIntent");synchronized(this) {//验证广播intent是否有效intent = verifyBroadcastLocked(intent);//获取调用者进程记录对象final ProcessRecord callerApp = getRecordForAppLocked(caller);final int callingPid = Binder.getCallingPid();final int callingUid = Binder.getCallingUid();final long origId = Binder.clearCallingIdentity();//见3.2节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;}}
broadcastIntent有两个boolean值参数serialized、sticky共同决定是普通广播,有效广播,还是sticky广播。
类型 | serialized | sticky |
---|---|---|
sendBroadcast | false | false |
sendOrderedBroadcast | true | false |
sendStickyBroadcast | false | true |
3.3 AMS.broadcastIntentLocked
[->ActivityManagerService.java]
@GuardedBy("this")final int broadcastIntentLocked(ProcessRecord callerApp,String callerPackage, Intent intent, String resolvedType,IIntentReceiver resultTo, int resultCode, String resultData,Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {//setp1:设置广播flags//setp2:广播权限验证//setp3:处理系统相关广播//setp4:增加sticky广播//setp5:查询receivers和registeredReceivers//setp6:处理并行广播//setp7:合并registeredReceivers到receivers//setp8:处理串行广播return ActivityManager.BROADCAST_SUCCESS;}
该方法比较长,这里分为8部分进行分析。
3.3.1 设置广播flags
intent = new Intent(intent);//判断是否是即时应用final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);//即时应用如果没有设置FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS则不会收到广播// Instant Apps cannot use FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPSif (callerInstantApp) {intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);}//增加flag,广播不会发送给已经停止的package// By default broadcasts do not go to stopped apps.intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);//系统没有启动完成,不允许启动新进程// If we have not finished booting, don't allow this to launch new processes.if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);}if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,(sticky ? "Broadcast sticky: ": "Broadcast: ") + intent+ " ordered=" + ordered + " userid=" + userId);if ((resultTo != null) && !ordered) {Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");}userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,ALLOW_NON_FULL, "broadcast", callerPackage);//检查发送广播时的用户状态// Make sure that the user who is receiving this broadcast or its parent is running.// If not, we will just skip it. Make an exception for shutdown broadcasts, upgrade steps.if (userId != UserHandle.USER_ALL && !mUserController.isUserOrItsParentRunning(userId)) {if ((callingUid != SYSTEM_UID|| (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)&& !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {Slog.w(TAG, "Skipping broadcast of " + intent+ ": user " + userId + " and its parent (if any) are stopped");return ActivityManager.BROADCAST_FAILED_USER_STOPPED;}}
这个过程主要的工作如下:
1.是否设置FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS标志,如果设置广播对即时应用可见;
2.添加flagFLAG_EXCLUDE_STOPPED_PACKAGES,保证已经停止的app不会收到广播;
3.当系统还没有启动完成,不允许启动新进程;
4.非USER_ALL广播且接收广播的用户没有处于Running的情况下,除非是系统升级广播和关键广播,否则直接返回。
BroadcastReceiver还有其他flag,位于Intent.java常量中:
FLAG_RECEIVER_REGISTERED_ONLY //只允许已经注册的receiver接收广播
FLAG_RECEIVER_REPLACE_PENDING //新广播会替代相同广播
FLAG_RECEIVER_FOREGROUND //只允许前台receiver接收广播
FLAG_RECEIVER_NO_ABORT //对于有序广播,先接收到的receiver无权抛弃广播
FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT //boot完成之前,只允许已注册的receiver接收广播
FLAG_RECEIVER_BOOT_UPGRADE //升级模式下,允许系统准备就绪前发送广播
FLAG_RECEIVER_INCLUDE_BACKGROUND //允许后台台receiver接收广播
FLAG_RECEIVER_EXCLUDE_BACKGROUND //不允许后台台receiver接收广播
FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS //广播对即时应用可见
3.3.2 广播权限验证
final String action = intent.getAction();BroadcastOptions brOptions = null;if (bOptions != null) {brOptions = new BroadcastOptions(bOptions);if (brOptions.getTemporaryAppWhitelistDuration() > 0) {//如果AppWhitelistDuration>0,检查是否有CHANGE_DEVICE_IDLE_TEMP_WHITELIST权限// See if the caller is allowed to do this. Note we are checking against// the actual real caller (not whoever provided the operation as say a// PendingIntent), because that who is actually supplied the arguments.if (checkComponentPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,Binder.getCallingPid(), Binder.getCallingUid(), -1, true)!= PackageManager.PERMISSION_GRANTED) {String msg = "Permission Denial: " + intent.getAction()+ " broadcast from " + callerPackage + " (pid=" + callingPid+ ", uid=" + callingUid + ")"+ " requires "+ android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;Slog.w(TAG, msg);throw new SecurityException(msg);}}//检查是否有后台限制if (brOptions.isDontSendToRestrictedApps()&& !isUidActiveLocked(callingUid)&& isBackgroundRestrictedNoCheck(callingUid, callerPackage)) {Slog.i(TAG, "Not sending broadcast " + action + " - app " + callerPackage+ " has background restrictions");return ActivityManager.START_CANCELED;}}//检查受保护的广播只允许系统使用// Verify that protected broadcasts are only being sent by system code,// and that system code is only sending protected broadcasts.final boolean isProtectedBroadcast;try {isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);} catch (RemoteException e) {Slog.w(TAG, "Remote exception", e);return ActivityManager.BROADCAST_SUCCESS;}final boolean isCallerSystem;switch (UserHandle.getAppId(callingUid)) {case ROOT_UID:case SYSTEM_UID:case PHONE_UID:case BLUETOOTH_UID:case NFC_UID:case SE_UID:case NETWORK_STACK_UID:isCallerSystem = true;break;default:isCallerSystem = (callerApp != null) && callerApp.persistent;break;}//非系统发送的广播// First line security check before anything else: stop non-system apps from// sending protected broadcasts.if (!isCallerSystem) {//是保护广播,则抛出异常if (isProtectedBroadcast) {String msg = "Permission Denial: not allowed to send broadcast "+ action + " from pid="+ callingPid + ", uid=" + callingUid;Slog.w(TAG, msg);throw new SecurityException(msg);} else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)|| AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {//限制广播只发送自己 // Special case for compatibility: we don't want apps to send this,// but historically it has not been protected and apps may be using it// to poke their own app widget. So, instead of making it protected,// just limit it to the caller.if (callerPackage == null) {String msg = "Permission Denial: not allowed to send broadcast "+ action + " from unknown caller.";Slog.w(TAG, msg);throw new SecurityException(msg);} else if (intent.getComponent() != null) {// They are good enough to send to an explicit component... verify// it is being sent to the calling app.if (!intent.getComponent().getPackageName().equals(callerPackage)) {String msg = "Permission Denial: not allowed to send broadcast "+ action + " to "+ intent.getComponent().getPackageName() + " from "+ callerPackage;Slog.w(TAG, msg);throw new SecurityException(msg);}} else {// Limit broadcast to their own package.intent.setPackage(callerPackage);}}}if (action != null) {//如果允许后台应用接收广播,则添加FLAG_RECEIVER_INCLUDE_BACKGROUNDif (getBackgroundLaunchBroadcasts().contains(action)) {if (DEBUG_BACKGROUND_CHECK) {Slog.i(TAG, "Broadcast action " + action + " forcing include-background");}intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);}
主要工作如下:
1.如果TemporaryAppWhitelistDuration>0,检查是否有CHANGE_DEVICE_IDLE_TEMP_WHITELIST权限,没有抛出异常
2.检查是否后台限制发送广播,如果限制,则后台应用将不能发送广播
3.callingUid为 ROOT_UID, SYSTEM_UID,PHONE_UID,BLUETOOTH_UID,NFC_UID,SE_UID,NETWORK_STACK_UID和persistent进程时,可以发送受保护广播
4.为非系统应用发送广播时:当发送的是受保护的广播,则抛出异常;当action为ACTION_APPWIDGET_CONFIGURE或ACTION_APPWIDGET_UPDATE时,限制该广播只发送给自己,否则抛出异常。
5.如果允许后台应用接收广播,则添加FLAG_RECEIVER_INCLUDE_BACKGROUND
3.3.3 处理系统相关广播
switch (action) {case Intent.ACTION_UID_REMOVED://uid移除case Intent.ACTION_PACKAGE_REMOVED://package移除case Intent.ACTION_PACKAGE_CHANGED://改变packagecase Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE://外部设备不可用case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:case Intent.ACTION_PACKAGES_SUSPENDED:case Intent.ACTION_PACKAGES_UNSUSPENDED:// Handle special intents: if this broadcast is from the package// manager about a package being removed, we need to remove all of// its activities from the history stack.if (checkComponentPermission(android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,callingPid, callingUid, -1, true)!= PackageManager.PERMISSION_GRANTED) {String msg = "Permission Denial: " + intent.getAction()+ " broadcast from " + callerPackage + " (pid=" + callingPid+ ", uid=" + callingUid + ")"+ " requires "+ android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;Slog.w(TAG, msg);throw new SecurityException(msg);}switch (action) {case Intent.ACTION_UID_REMOVED:final int uid = getUidFromIntent(intent);if (uid >= 0) {mBatteryStatsService.removeUid(uid);mAppOpsService.uidRemoved(uid);}break;case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:// If resources are unavailable just force stop all those packages// and flush the attribute cache as well.String list[] =intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);if (list != null && list.length > 0) {for (int i = 0; i < list.length; i++) {forceStopPackageLocked(list[i], -1, false, true, true,false, false, userId, "storage unmount");}mRecentTasks.cleanupLocked(UserHandle.USER_ALL);sendPackageBroadcastLocked(ApplicationThreadConstants.EXTERNAL_STORAGE_UNAVAILABLE,list, userId);}break;case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:mRecentTasks.cleanupLocked(UserHandle.USER_ALL);break;case Intent.ACTION_PACKAGE_REMOVED:case Intent.ACTION_PACKAGE_CHANGED:Uri data = intent.getData();String ssp;if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action);final boolean replacing =intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);final boolean killProcess =!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false);final boolean fullUninstall = removed && !replacing;if (removed) {if (killProcess) {forceStopPackageLocked(ssp, UserHandle.getAppId(intent.getIntExtra(Intent.EXTRA_UID, -1)),false, true, true, false, fullUninstall, userId,removed ? "pkg removed" : "pkg changed");}final int cmd = killProcess? ApplicationThreadConstants.PACKAGE_REMOVED: ApplicationThreadConstants.PACKAGE_REMOVED_DONT_KILL;sendPackageBroadcastLocked(cmd,new String[] {ssp}, userId);if (fullUninstall) {mAppOpsService.packageRemoved(intent.getIntExtra(Intent.EXTRA_UID, -1), ssp);// Remove all permissions granted from/to this packageremoveUriPermissionsForPackageLocked(ssp, userId, true,false);mRecentTasks.removeTasksByPackageName(ssp, userId);mServices.forceStopPackageLocked(ssp, userId);mAppWarnings.onPackageUninstalled(ssp);mCompatModePackages.handlePackageUninstalledLocked(ssp);mBatteryStatsService.notePackageUninstalled(ssp);}} else {if (killProcess) {killPackageProcessesLocked(ssp, UserHandle.getAppId(intent.getIntExtra(Intent.EXTRA_UID, -1)),userId, ProcessList.INVALID_ADJ,false, true, true, false, "change " + ssp);}cleanupDisabledPackageComponentsLocked(ssp, userId, killProcess,intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST));}}break;case Intent.ACTION_PACKAGES_SUSPENDED:case Intent.ACTION_PACKAGES_UNSUSPENDED:final boolean suspended = Intent.ACTION_PACKAGES_SUSPENDED.equals(intent.getAction());final String[] packageNames = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);synchronized(ActivityManagerService.this) {mRecentTasks.onPackagesSuspendedChanged(packageNames, suspended, userHandle);}break;}break;case Intent.ACTION_PACKAGE_REPLACED:{final Uri data = intent.getData();final String ssp;if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {ApplicationInfo aInfo = null;try {aInfo = AppGlobals.getPackageManager().getApplicationInfo(ssp, STOCK_PM_FLAGS, userId);} catch (RemoteException ignore) {}if (aInfo == null) {Slog.w(TAG, "Dropping ACTION_PACKAGE_REPLACED for non-existent pkg:"+ " ssp=" + ssp + " data=" + data);return ActivityManager.BROADCAST_SUCCESS;}mStackSupervisor.updateActivityApplicationInfoLocked(aInfo);mServices.updateServiceApplicationInfoLocked(aInfo);sendPackageBroadcastLocked(ApplicationThreadConstants.PACKAGE_REPLACED,new String[] {ssp}, userId);}break;}case Intent.ACTION_PACKAGE_ADDED:{// Special case for adding a package: by default turn on compatibility mode.Uri data = intent.getData();String ssp;if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {final boolean replacing =intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);mCompatModePackages.handlePackageAddedLocked(ssp, replacing);try {ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(ssp, STOCK_PM_FLAGS, 0);mBatteryStatsService.notePackageInstalled(ssp,ai != null ? ai.versionCode : 0);} catch (RemoteException e) {}}break;}case Intent.ACTION_PACKAGE_DATA_CLEARED:{Uri data = intent.getData();String ssp;if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {mCompatModePackages.handlePackageDataClearedLocked(ssp);mAppWarnings.onPackageDataCleared(ssp);}break;}case Intent.ACTION_TIMEZONE_CHANGED:// If this is the time zone changed action, queue up a message that will reset// the timezone of all currently running processes. This message will get// queued up before the broadcast happens.mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);break;case Intent.ACTION_TIME_CHANGED:// EXTRA_TIME_PREF_24_HOUR_FORMAT is optional so we must distinguish between// the tri-state value it may contain and "unknown".// For convenience we re-use the Intent extra values.final int NO_EXTRA_VALUE_FOUND = -1;final int timeFormatPreferenceMsgValue = intent.getIntExtra(Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT,NO_EXTRA_VALUE_FOUND /* defaultValue */);// Only send a message if the time preference is available.if (timeFormatPreferenceMsgValue != NO_EXTRA_VALUE_FOUND) {Message updateTimePreferenceMsg =mHandler.obtainMessage(UPDATE_TIME_PREFERENCE_MSG,timeFormatPreferenceMsgValue, 0);mHandler.sendMessage(updateTimePreferenceMsg);}BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();synchronized (stats) {stats.noteCurrentTimeChangedLocked();}break;case Intent.ACTION_CLEAR_DNS_CACHE: //清除DNS cachemHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);break;case Proxy.PROXY_CHANGE_ACTION: //网络代理改变mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG));break;case android.hardware.Camera.ACTION_NEW_PICTURE:case android.hardware.Camera.ACTION_NEW_VIDEO:// In N we just turned these off; in O we are turing them back on partly,// only for registered receivers. This will still address the main problem// (a spam of apps waking up when a picture is taken putting significant// memory pressure on the system at a bad point), while still allowing apps// that are already actively running to know about this happening.intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);break;case android.security.KeyChain.ACTION_TRUST_STORE_CHANGED:mHandler.sendEmptyMessage(HANDLE_TRUST_STORAGE_UPDATE_MSG);break;case "com.android.launcher.action.INSTALL_SHORTCUT":// As of O, we no longer support this broadcasts, even for pre-O apps.// Apps should now be using ShortcutManager.pinRequestShortcut().Log.w(TAG, "Broadcast " + action+ " no longer supported. It will not be delivered.");return ActivityManager.BROADCAST_SUCCESS;}if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||Intent.ACTION_PACKAGE_REMOVED.equals(action) ||Intent.ACTION_PACKAGE_REPLACED.equals(action)) {final int uid = getUidFromIntent(intent);if (uid != -1) {final UidRecord uidRec = mActiveUids.get(uid);if (uidRec != null) {uidRec.updateHasInternetPermission();}}}}
该过程主要系统广播,主要是package、时间、网络相关的广播,并对这些广播进行相应的处理。
3.3.4 增加sticky广播
// Add to the sticky list if requested.if (sticky) {//检查是否有BROADCAST_STICKY权限if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,callingPid, callingUid)!= PackageManager.PERMISSION_GRANTED) {String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="+ callingPid + ", uid=" + callingUid+ " requires " + android.Manifest.permission.BROADCAST_STICKY;Slog.w(TAG, msg);throw new SecurityException(msg);}if (requiredPermissions != null && requiredPermissions.length > 0) {Slog.w(TAG, "Can't broadcast sticky intent " + intent+ " and enforce permissions " + Arrays.toString(requiredPermissions));return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;}//发送指定组件,抛出异常if (intent.getComponent() != null) {throw new SecurityException("Sticky broadcasts can't target a specific component");}//当非USER_ALL广播和USER_ALL冲突// We use userId directly here, since the "all" target is maintained// as a separate set of sticky broadcasts.if (userId != UserHandle.USER_ALL) {// But first, if this is not a broadcast to all users, then// make sure it doesn't conflict with an existing broadcast to// all users.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))) {throw new IllegalArgumentException("Sticky broadcast " + intent + " for user "+ userId + " conflicts with existing global broadcast");}}}}}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));}}
这个过程主要是检查sticky广播,将sticky广播放入到mStickyBroadcasts,并增加到list
3.3.5 查询receivers和registeredReceivers
//发送广播的userint[] users;if (userId == UserHandle.USER_ALL) {// Caller wants broadcast to go to all started users.users = mUserController.getStartedUserArray();} else {// Caller wants broadcast to go to one specific user.users = new int[] {userId};}//查询哪些广播将会接受广播// Figure out who all will receive this broadcast.List receivers = null;List<BroadcastFilter> registeredReceivers = null;// Need to resolve the intent to interested receivers...//当允许静态接收者处理广播时,则通过PKMS根据intent查询静态receiversif ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)== 0) {receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);}if (intent.getComponent() == null) {if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {// Query one target user at a time, excluding shell-restricted usersfor (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 /*defaultOnly*/, users[i]);if (registeredReceivers == null) {registeredReceivers = registeredReceiversForUser;} else if (registeredReceiversForUser != null) {registeredReceivers.addAll(registeredReceiversForUser);}}} else {registeredReceivers = mReceiverResolver.queryIntent(intent,resolvedType, false /*defaultOnly*/, userId);}}
主要工作如下:
1.根据userId判断发送的是全部的接收者还是指定的userId
2.查询广播,并将其放入到两个列表:
registeredReceivers:来匹配当前intent的所有动态注册的广播接收者(mReceiverResolver见2.4节)
receivers:记录当前intent的所有静态注册的广播接收者
private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,int callingUid, int[] users) {...//调用PKMS的queryIntentReceivers,可以获取AndroidManifeset中注册的接收信息List<ResolveInfo> newReceivers = AppGlobals.getPackageManager().queryIntentReceivers(intent, resolvedType, pmFlags, user).getList();... return receivers;}
3.3.6 处理并行广播
//用于标识是否需要用新的intent替换旧的intentfinal boolean replacePending =(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing 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.//检查系统发送的广播if (isCallerSystem) {checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,isProtectedBroadcast, registeredReceivers);}//根据intent的flag来判断前台队列还是后台队列,见2.4.3节final BroadcastQueue queue = broadcastQueueForIntent(intent);//创建BroadcastRecordBroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,callerPackage, callingPid, callingUid, callerInstantApp, 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) != null);// Note: We assume resultTo is null for non-ordered broadcasts.if (!replaced) {//将BroadcastRecord加入到并行广播队列queue.enqueueParallelBroadcastLocked(r);//处理广播,见4.1节queue.scheduleBroadcastsLocked();}//动态注册的广播接收者处理完成,则将该变量设置为空registeredReceivers = null;NR = 0;}
广播队列中有一个mParallelBroadcasts变量,类型为ArrayList,记录所有的并行广播
public void enqueueParallelBroadcastLocked(BroadcastRecord r) {mParallelBroadcasts.add(r);enqueueBroadcastHelper(r);}
3.3.7 合并registeredReceivers到receivers
// Merge into one list.int ir = 0;if (receivers != null) {//防止应用监听广播,在安装时直接运行// A special case for PACKAGE_ADDED: do not allow the package// being added to see this broadcast. This prevents them from// using this as a back door to get run as soon as they are// installed. Maybe in the future we want to have a special install// broadcast or such for apps, but we'd like to deliberately make// this decision.String skipPackages[] = null;if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())|| Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())|| Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {Uri data = intent.getData();if (data != null) {String pkgName = data.getSchemeSpecificPart();if (pkgName != null) {skipPackages = new String[] { pkgName };}}} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);}//将skipPackages相关的广播接收者从receivers列表中移除。if (skipPackages != null && (skipPackages.length > 0)) {for (String skipPackage : skipPackages) {if (skipPackage != null) {int NT = receivers.size();for (int it=0; it<NT; it++) {ResolveInfo curt = (ResolveInfo)receivers.get(it);if (curt.activityInfo.packageName.equals(skipPackage)) {receivers.remove(it);it--;NT--;}}}}}//3.4.6节有处理动态广播的过程,处理完成后再执行将动态注册的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);}//优先级大的,则插到前面if (curr.getPriority() >= curt.priority) {// Insert this broadcast record into the final list.receivers.add(it, curr);ir++;curr = null;it++;NT++;} else {// Skip to the next ResolveInfo in the final list.it++;curt = null;}}}while (ir < NR) {if (receivers == null) {receivers = new ArrayList();}receivers.add(registeredReceivers.get(ir));ir++;}//检查系统发送的广播if (isCallerSystem) {checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,isProtectedBroadcast, receivers);}
这里主要是将动态注册的registeredReceivers(如果发送的广播不是有序广播则registeredReceivers = null)全部合并到receivers,再统一按照串行方式处理。
3.3.8 处理串行广播
if ((receivers != null && receivers.size() > 0)|| resultTo != null) {//根据intent的flag判断是前台队列还是后台队列,见2.4.3节 BroadcastQueue queue = broadcastQueueForIntent(intent);//创建BroadcastRecordBroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,callerPackage, callingPid, callingUid, callerInstantApp, 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());final BroadcastRecord oldRecord =replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;if (oldRecord != null) {// Replaced, fire the result-to receiver.if (oldRecord.resultTo != null) {final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);try {oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,oldRecord.intent,Activity.RESULT_CANCELED, null, null,false, false, oldRecord.userId);} catch (RemoteException e) {Slog.w(TAG, "Failure ["+ queue.mQueueName + "] sending broadcast result of "+ intent, e);}}} else {//将BroadcastRecord加入到有序广播队列queue.enqueueOrderedBroadcastLocked(r);//处理广播,见4.1节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);}}
广播队列中有一个mOrderedBroadcasts变量,类型为ArrayList,记录所有的有序广播
//串行广播加入到mOrderedBroadcasts队列
public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {mOrderedBroadcasts.add(r);enqueueBroadcastHelper(r);}
3.4 小结
发送广播的过程:
1.默认不发送给已停止的(FLAG_EXCLUDE_STOPPED_PACKAGES)应用和即时应用(需要添加该FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS标记才可以)
2.对广播进行权限验证,是否是受保护的广播,是否允许后台接收广播,是否允许后台发送广播
3.处理系统广播,主要是package、时间、网络相关的广播
4.当为粘性广播时,将sticky广播增加到list,并放入mStickyBroadcasts队列
5.当广播的intent没有设置FLAG_RECEIVER_REGISTERED_ONLY,则允许静态广播接收者来处理该广播;创建BroadcastRecord对象,并将该对象加入到相应的广播队列,然后调用BroadcastQueue的scheduleBroadcastsLocked方法来完成不同广播的处理。
不同广播的处理方式:
1.sticky广播:广播注册过程中处理AMS.registerReceiver,开始处理粘性广播,见2.4节
- 创建BroadcastRecord对象
- 添加到mParallelBroadcasts队列
- 然后执行 queue.scheduleBroadcastsLocked()
2.并行广播:广播发送处理过程见3.3.6节
- 只有动态注册的registeredReceivers才会进行并行处理
- 创建BroadcastRecord对象
- 添加到mParallelBroadcasts队列
- 然后执行 queue.scheduleBroadcastsLocked()
3.串行广播:广播发送处理过程见3.3.8节
- 所有静态注册的receivers以及动态注册的registeredReceivers(发送的广播是有序广播)合并到一张表处理
- 创建BroadcastRecord对象
- 添加到mOrderedBroadcasts队列
- 然后执行 queue.scheduleBroadcastsLocked()
从上面可以看出,不管哪种广播方式,都是通过broadcastQueueForIntent来根据intent的flag判段是前台队列还是后台队列广播,然后再调用对应广播队列的scheduleBroadcastsLocked方法来处理广播。
四、接收广播
在发送广播的过程会执行scheduleBroadcastsLocked方法来处理广播
4.1 BQ.scheduleBroadcastsLocked
[->BroadcastQueue.java]
public void scheduleBroadcastsLocked() {if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["+ mQueueName + "]: current="+ mBroadcastsScheduled);//正在处理BROADCAST_INTENT_MSG消息if (mBroadcastsScheduled) {return;}//发送BROADCAST_INTENT_MSG消息mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));mBroadcastsScheduled = true;}
4.1.1 BroadcastHandler
[->BroadcastQueue.java]
private final class BroadcastHandler extends Handler {public BroadcastHandler(Looper looper) {super(looper, null, true);}@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case BROADCAST_INTENT_MSG: {if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");//见4.2节processNextBroadcast(true);} break;case BROADCAST_TIMEOUT_MSG: {synchronized (mService) {broadcastTimeoutLocked(true);}} break;}}}
发送BROADCAST_INTENT_MSG消息后,BroadcastHandler进行处理,其初始化在构造函数中创建,而BroadcastQueue是在AMS初始化,从源码中可以看出handler采用的是"ActivityManagerService"线程的loop。
BroadcastQueue(ActivityManagerService service, Handler handler,String name, long timeoutPeriod, boolean allowDelayBehindServices) {mService = service;//创建BroadcastHandlermHandler = new BroadcastHandler(handler.getLooper());mQueueName = name;mTimeoutPeriod = timeoutPeriod;mDelayBehindServices = allowDelayBehindServices;}public ActivityManagerService(Context systemContext) {...//名为ActivityManagerService的线程mHandlerThread = new ServiceThread(TAG,THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);mHandlerThread.start();mHandler = new MainHandler(mHandlerThread.getLooper());//创建BroadcastQueue对象mFgBroadcastQueue = new BroadcastQueue(this, mHandler,"foreground", BROADCAST_FG_TIMEOUT, false);mBgBroadcastQueue = new BroadcastQueue(this, mHandler,"background", BROADCAST_BG_TIMEOUT, true);//android10.0新增加的一个分流队列,目前仅处理BOOT_COMPLETED广播// Convenient for easy iteration over the queues. Foreground is first// so that dispatch of foreground broadcasts gets precedence.final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[2];...} //广播超时时间定义// How long we allow a receiver to run before giving up on it.static final int BROADCAST_FG_TIMEOUT = 10*1000;static final int BROADCAST_BG_TIMEOUT = 60*1000;
4.2 BQ.processNextBroadcast
[->BroadcastQueue.java]
final void processNextBroadcast(boolean fromMsg) {//同步mServicesynchronized (mService) {processNextBroadcastLocked(fromMsg, false);}}
此次mService为AMS,整个流程比较长,全程持有AMS锁,所以广播效率低下的情况下,直接会严重影响手机的性能和流畅度,这里是否应考虑细化同步锁的粒度。
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {//setp1:处理并行广播//setp2:处理串行广播//setp3:获取下条有序广播//setp4:处理下条有序广播 }
整个处理的过程比较长,将分为四个部分进行分析。
4.2.1 处理并行广播
BroadcastRecord r;if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast ["+ mQueueName + "]: "+ mParallelBroadcasts.size() + " parallel broadcasts, "+ mOrderedBroadcasts.size() + " ordered broadcasts");//更新cpu统计信息mService.updateCpuStats();//方法传进来的是true,将mBroadcastsScheduled重置为falseif (fromMsg) {mBroadcastsScheduled = false;}// 处理并行队列// First, deliver any non-serialized broadcasts right away.while (mParallelBroadcasts.size() > 0) {r = mParallelBroadcasts.remove(0);r.dispatchTime = SystemClock.uptimeMillis();r.dispatchClockTime = System.currentTimeMillis();if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),System.identityHashCode(r));Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),System.identityHashCode(r));}final int N = r.receivers.size();if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["+ mQueueName + "] " + r);for (int i=0; i<N; i++) {Object target = r.receivers.get(i);if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Delivering non-ordered on [" + mQueueName + "] to registered "+ target + ": " + r);//分发广播给已经注册的receiver,见4.3节deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);}//将广播添加到历史记录addBroadcastToHistoryLocked(r); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["+ mQueueName + "] " + r);}
通过while循环,每次取出一个,一次性分发完所有的并发广播后,将分发完成的添加到历史广播队列。
4.2.2 处理串行广播
// Now take care of the next serialized one...// If we are waiting for a process to come up to handle the next// broadcast, then do nothing at this point. Just in case, we// check that the process we're waiting for still exists.if (mPendingBroadcast != null) {if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,"processNextBroadcast [" + mQueueName + "]: waiting for "+ mPendingBroadcast.curApp);boolean isDead;if (mPendingBroadcast.curApp.pid > 0) {synchronized (mService.mPidsSelfLocked) {//从mPidsSelfLocked获取正在处理的广播进程,判断进程是否死亡ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);isDead = proc == null || proc.crashing;}} else {//从mProcessNames获取正在处理的广播进程,判断进程是否死亡final ProcessRecord proc = mService.mProcessNames.get(mPendingBroadcast.curApp.processName, mPendingBroadcast.curApp.uid);isDead = proc == null || !proc.pendingStart;}if (!isDead) {// 如果正在处理广播的进程保持活跃状态,则继续等待其执行完成// It's still alive, so keep waitingreturn;} else {Slog.w(TAG, "pending app ["+ mQueueName + "]" + mPendingBroadcast.curApp+ " died before responding to broadcast");mPendingBroadcast.state = BroadcastRecord.IDLE;mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;mPendingBroadcast = null;}}boolean looped = false;do {if (mOrderedBroadcasts.size() == 0) {// No more broadcasts pending, so all done!//所有的串行广播处理完成,则调度执行gcmService.scheduleAppGcsLocked();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;//系统进程已经准备好if (mService.mProcessesReady && r.dispatchTime > 0) {long now = SystemClock.uptimeMillis();if ((numReceivers > 0) &&(now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {Slog.w(TAG, "Hung broadcast ["+ mQueueName + "] discarded after timeout failure:"+ " now=" + now+ " dispatchTime=" + r.dispatchTime+ " startTime=" + r.receiverTime+ " intent=" + r.intent+ " numReceivers=" + numReceivers+ " nextReceiver=" + r.nextReceiver+ " state=" + r.state);//广播超时,强制结束这条广播 broadcastTimeoutLocked(false); // forcibly finish this broadcastforceReceive = true;r.state = BroadcastRecord.IDLE;}}if (r.state != BroadcastRecord.IDLE) {if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST,"processNextBroadcast("+ mQueueName + ") called when not idle (state="+ r.state + ")");return;}if (r.receivers == null || r.nextReceiver >= numReceivers|| r.resultAbort || forceReceive) {// No more receivers for this broadcast! Send the final// result if requested...if (r.resultTo != null) {try {if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,"Finishing broadcast [" + mQueueName + "] "+ r.intent.getAction() + " app=" + r.callerApp);//处理广播消息,调用到onReceive() 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;Slog.w(TAG, "Failure ["+ mQueueName + "] sending broadcast result of "+ r.intent, e);}}if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");//取消BROADCAST_TIMEOUT_MSG消息cancelBroadcastTimeoutLocked();if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,"Finished with ordered broadcast " + r);// 添加到队列消息记录// ... 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);r = null;looped = true;continue;}} while (r == null);
mTimeoutPeriod,对于前台广播为10s,后台广播为60s。广播超时为2 * mTimeoutPeriod * numReceivers,接收者个数numReceivers越多,则广播超时总时间越大。
4.2.3 获取下条有序广播
//获取下条广播的index// Get the next receiver...int recIdx = r.nextReceiver++;// 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) {r.dispatchTime = r.receiverTime;r.dispatchClockTime = System.currentTimeMillis();if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),System.identityHashCode(r));Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),System.identityHashCode(r));}if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast ["+ mQueueName + "] " + r);}if (! mPendingBroadcastTimeoutMessage) {long timeoutTime = r.receiverTime + mTimeoutPeriod;if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Submitting BROADCAST_TIMEOUT_MSG ["+ mQueueName + "] for " + r + " at " + timeoutTime);//发送广播超时 setBroadcastTimeoutLocked(timeoutTime);}final BroadcastOptions brOptions = r.options;final Object nextReceiver = r.receivers.get(recIdx);if (nextReceiver instanceof BroadcastFilter) {// Simple case: this is a registered receiver who gets// a direct call.//对于动态注册的广播接收者BroadcastFilter filter = (BroadcastFilter)nextReceiver;if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Delivering ordered ["+ mQueueName + "] to registered "+ filter + ": " + r);//处理广播,见4.3节 deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);if (r.receiver == null || !r.ordered) {// The receiver has already finished, so schedule to// process the next one.if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["+ mQueueName + "]: ordered="+ r.ordered + " receiver=" + r.receiver);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;ComponentName component = new ComponentName(info.activityInfo.applicationInfo.packageName,info.activityInfo.name);//下面都是各种检查权限,权限不满足时则跳过boolean skip = false;if (brOptions != null &&(info.activityInfo.applicationInfo.targetSdkVersion< brOptions.getMinManifestReceiverApiLevel() ||info.activityInfo.applicationInfo.targetSdkVersion> brOptions.getMaxManifestReceiverApiLevel())) {skip = true; //sdk版本,Androidmanifest中设置}int perm = mService.checkComponentPermission(info.activityInfo.permission,r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,info.activityInfo.exported);//Component权限if (!skip && perm != PackageManager.PERMISSION_GRANTED) {if (!info.activityInfo.exported) {Slog.w(TAG, "Permission Denial: broadcasting "+ r.intent.toString()+ " from " + r.callerPackage + " (pid=" + r.callingPid+ ", uid=" + r.callingUid + ")"+ " is not exported from uid " + info.activityInfo.applicationInfo.uid+ " due to receiver " + component.flattenToShortString());} else {Slog.w(TAG, "Permission Denial: broadcasting "+ r.intent.toString()+ " from " + r.callerPackage + " (pid=" + r.callingPid+ ", uid=" + r.callingUid + ")"+ " requires " + info.activityInfo.permission+ " due to receiver " + component.flattenToShortString());}skip = true;} else if (!skip && info.activityInfo.permission != null) {final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission);if (opCode != AppOpsManager.OP_NONE&& mService.mAppOpsService.noteOperation(opCode, r.callingUid,r.callerPackage) != AppOpsManager.MODE_ALLOWED) {Slog.w(TAG, "Appop Denial: broadcasting "+ r.intent.toString()+ " from " + r.callerPackage + " (pid="+ r.callingPid + ", uid=" + r.callingUid + ")"+ " requires appop " + AppOpsManager.permissionToOp(info.activityInfo.permission)+ " due to registered receiver "+ component.flattenToShortString());skip = true;}}if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&r.requiredPermissions != null && r.requiredPermissions.length > 0) {for (int i = 0; i < r.requiredPermissions.length; i++) {String requiredPermission = r.requiredPermissions[i];try {perm = AppGlobals.getPackageManager().checkPermission(requiredPermission,info.activityInfo.applicationInfo.packageName,UserHandle.getUserId(info.activityInfo.applicationInfo.uid));} catch (RemoteException e) {perm = PackageManager.PERMISSION_DENIED;}if (perm != PackageManager.PERMISSION_GRANTED) {Slog.w(TAG, "Permission Denial: receiving "+ r.intent + " to "+ component.flattenToShortString()+ " requires " + requiredPermission+ " due to sender " + r.callerPackage+ " (uid " + r.callingUid + ")");skip = true;break;}int appOp = AppOpsManager.permissionToOpCode(requiredPermission);if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp&& mService.mAppOpsService.noteOperation(appOp,info.activityInfo.applicationInfo.uid, info.activityInfo.packageName)!= AppOpsManager.MODE_ALLOWED) {Slog.w(TAG, "Appop Denial: receiving "+ r.intent + " to "+ component.flattenToShortString()+ " requires appop " + AppOpsManager.permissionToOp(requiredPermission)+ " due to sender " + r.callerPackage+ " (uid " + r.callingUid + ")");skip = true;break;}}}if (!skip && r.appOp != AppOpsManager.OP_NONE&& mService.mAppOpsService.noteOperation(r.appOp,info.activityInfo.applicationInfo.uid, info.activityInfo.packageName)!= AppOpsManager.MODE_ALLOWED) {Slog.w(TAG, "Appop Denial: receiving "+ r.intent + " to "+ component.flattenToShortString()+ " requires appop " + AppOpsManager.opToName(r.appOp)+ " due to sender " + r.callerPackage+ " (uid " + r.callingUid + ")");skip = true;}if (!skip) {skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid);}boolean isSingleton = false;try {isSingleton = mService.isSingleton(info.activityInfo.processName,info.activityInfo.applicationInfo,info.activityInfo.name, info.activityInfo.flags);} catch (SecurityException e) {Slog.w(TAG, e.getMessage());skip = true;}if ((info.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) {if (ActivityManager.checkUidPermission(android.Manifest.permission.INTERACT_ACROSS_USERS,info.activityInfo.applicationInfo.uid)!= PackageManager.PERMISSION_GRANTED) {Slog.w(TAG, "Permission Denial: Receiver " + component.flattenToShortString()+ " requests FLAG_SINGLE_USER, but app does not hold "+ android.Manifest.permission.INTERACT_ACROSS_USERS);skip = true;}}if (!skip && info.activityInfo.applicationInfo.isInstantApp()&& r.callingUid != info.activityInfo.applicationInfo.uid) {Slog.w(TAG, "Instant App Denial: receiving "+ r.intent+ " to " + component.flattenToShortString()+ " due to sender " + r.callerPackage+ " (uid " + r.callingUid + ")"+ " Instant Apps do not support manifest receivers");skip = true;}if (!skip && r.callerInstantApp&& (info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0&& r.callingUid != info.activityInfo.applicationInfo.uid) {Slog.w(TAG, "Instant App Denial: receiving "+ r.intent+ " to " + component.flattenToShortString()+ " requires receiver have visibleToInstantApps set"+ " due to sender " + r.callerPackage+ " (uid " + r.callingUid + ")");skip = true;}if (r.curApp != null && r.curApp.crashing) {// If the target process is crashing, just skip it.Slog.w(TAG, "Skipping deliver ordered [" + mQueueName + "] " + r+ " to " + r.curApp + ": process crashing");skip = true;}if (!skip) {boolean isAvailable = false;try {isAvailable = AppGlobals.getPackageManager().isPackageAvailable(info.activityInfo.packageName,UserHandle.getUserId(info.activityInfo.applicationInfo.uid));} catch (Exception e) {// all such failures mean we skip this receiverSlog.w(TAG, "Exception getting recipient info for "+ info.activityInfo.packageName, e);}if (!isAvailable) {if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Skipping delivery to " + info.activityInfo.packageName + " / "+ info.activityInfo.applicationInfo.uid+ " : package no longer available");skip = true;}}// If permissions need a review before any of the app components can run, we drop// the broadcast and if the calling app is in the foreground and the broadcast is// explicit we launch the review UI passing it a pending intent to send the skipped// broadcast.if (mService.mPermissionReviewRequired && !skip) {if (!requestStartTargetPermissionsReviewIfNeededLocked(r,info.activityInfo.packageName, UserHandle.getUserId(info.activityInfo.applicationInfo.uid))) {skip = true;}}// 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);if (!skip) {final int allowed = mService.getAppStartModeLocked(info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false, false);if (allowed != ActivityManager.APP_START_MODE_NORMAL) {// We won't allow this receiver to be launched if the app has been// completely disabled from launches, or it was not explicitly sent// to it and the app is in a state that should not receive it// (depending on how getAppStartModeLocked has determined that).if (allowed == ActivityManager.APP_START_MODE_DISABLED) {Slog.w(TAG, "Background execution disabled: receiving "+ r.intent + " to "+ component.flattenToShortString());skip = true;} else if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)|| (r.intent.getComponent() == null&& r.intent.getPackage() == null&& ((r.intent.getFlags()& Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0)&& !isSignaturePerm(r.requiredPermissions))) {mService.addBackgroundCheckViolationLocked(r.intent.getAction(),component.getPackageName());Slog.w(TAG, "Background execution not allowed: receiving "+ r.intent + " to "+ component.flattenToShortString());skip = true;}}}if (!skip && !Intent.ACTION_SHUTDOWN.equals(r.intent.getAction())&& !mService.mUserController.isUserRunning(UserHandle.getUserId(info.activityInfo.applicationInfo.uid),0 /* flags */)) {skip = true;Slog.w(TAG,"Skipping delivery to " + info.activityInfo.packageName + " / "+ info.activityInfo.applicationInfo.uid + " : user is not running");}//跳过该广播if (skip) {if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Skipping delivery of ordered [" + mQueueName + "] "+ r + " for whatever reason");r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;r.receiver = null;r.curFilter = null;r.state = BroadcastRecord.IDLE;r.manifestSkipCount++;scheduleBroadcastsLocked();return;}r.manifestCount++;r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;r.state = BroadcastRecord.APP_RECEIVE;r.curComponent = component;r.curReceiver = info.activityInfo;if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) {Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "+ info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "+ receiverUid);}if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {scheduleTempWhitelistLocked(receiverUid,brOptions.getTemporaryAppWhitelistDuration(), r);}// Broadcast正在执行,stopped状态设置成false// 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) {Slog.w(TAG, "Failed trying to unstop package "+ r.curComponent.getPackageName() + ": " + e);}
发送广播超时,如果是动态注册的广播则执行deliverToRegisteredReceiverLocked方法,如果是静态注册的广播,则进行一系列的权限检查,不满足则跳过该广播。
4.2.4 处理下条有序广播
// Is this receiver's application already running?if (app != null && app.thread != null && !app.killed) {// 接收广播的进程还在运行try {app.addPackage(info.activityInfo.packageName,info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);processCurBroadcastLocked(r, app, skipOomAdj);return;} catch (RemoteException e) {Slog.w(TAG, "Exception when sending broadcast to "+ r.curComponent, e);} catch (RuntimeException e) {Slog.wtf(TAG, "Failed sending broadcast to "+ r.curComponent + " with " + r.intent, e);// If some unexpected exception happened, just skip// this broadcast. At this point we are not in the call// from a client, so throwing an exception out from here// will crash the entire system instead of just whoever// sent the broadcast.logBroadcastReceiverDiscardLocked(r);finishReceiverLocked(r, r.resultCode, r.resultData,r.resultExtras, r.resultAbort, false);scheduleBroadcastsLocked();//如果启动receiver失败,则重置状态// 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 (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Need to start app ["+ mQueueName + "] " + targetProcess + " for broadcast " + r);//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 + "/"+ receiverUid + " for broadcast "+ r.intent + ": process is bad");//创建失败,直接结束该receiver logBroadcastReceiverDiscardLocked(r);finishReceiverLocked(r, r.resultCode, r.resultData,r.resultExtras, r.resultAbort, false);//开启下一个广播scheduleBroadcastsLocked();r.state = BroadcastRecord.IDLE;return;}mPendingBroadcast = r;mPendingBroadcastRecvIndex = recIdx;
-
如果是动态广播接收者,则调用deliverToRegisteredReceiverLocked处理
-
如果是静态广播接收者,且对应进程已经创建,则调用processCurBroadcastLocked处理
-
如果是静态广播接收者,且对应进程未创建,则调用startProcessLocked创建进程
4.3 BQ.deliverToRegisteredReceiverLocked
[->BroadcastQueue.java]
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,BroadcastFilter filter, boolean ordered, int index) {boolean skip = false;//检查发送者是否有BroadcastFilter所需要的权限if (filter.requiredPermission != null) {int perm = mService.checkComponentPermission(filter.requiredPermission,r.callingPid, r.callingUid, -1, true);if (perm != PackageManager.PERMISSION_GRANTED) {Slog.w(TAG, "Permission Denial: broadcasting "+ r.intent.toString()+ " from " + r.callerPackage + " (pid="+ r.callingPid + ", uid=" + r.callingUid + ")"+ " requires " + filter.requiredPermission+ " due to registered receiver " + filter);skip = true;} else {final int opCode = AppOpsManager.permissionToOpCode(filter.requiredPermission);if (opCode != AppOpsManager.OP_NONE&& mService.mAppOpsService.noteOperation(opCode, r.callingUid,r.callerPackage) != AppOpsManager.MODE_ALLOWED) {Slog.w(TAG, "Appop Denial: broadcasting "+ r.intent.toString()+ " from " + r.callerPackage + " (pid="+ r.callingPid + ", uid=" + r.callingUid + ")"+ " requires appop " + AppOpsManager.permissionToOp(filter.requiredPermission)+ " due to registered receiver " + filter);skip = true;}}}if (!skip && r.requiredPermissions != null && r.requiredPermissions.length > 0) {for (int i = 0; i < r.requiredPermissions.length; i++) {String requiredPermission = r.requiredPermissions[i];int perm = mService.checkComponentPermission(requiredPermission,filter.receiverList.pid, filter.receiverList.uid, -1, true);if (perm != PackageManager.PERMISSION_GRANTED) {Slog.w(TAG, "Permission Denial: receiving "+ r.intent.toString()+ " to " + filter.receiverList.app+ " (pid=" + filter.receiverList.pid+ ", uid=" + filter.receiverList.uid + ")"+ " requires " + requiredPermission+ " due to sender " + r.callerPackage+ " (uid " + r.callingUid + ")");skip = true;break;}int appOp = AppOpsManager.permissionToOpCode(requiredPermission);if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp&& mService.mAppOpsService.noteOperation(appOp,filter.receiverList.uid, filter.packageName)!= AppOpsManager.MODE_ALLOWED) {Slog.w(TAG, "Appop Denial: receiving "+ r.intent.toString()+ " to " + filter.receiverList.app+ " (pid=" + filter.receiverList.pid+ ", uid=" + filter.receiverList.uid + ")"+ " requires appop " + AppOpsManager.permissionToOp(requiredPermission)+ " due to sender " + r.callerPackage+ " (uid " + r.callingUid + ")");skip = true;break;}}}if (!skip && (r.requiredPermissions == null || r.requiredPermissions.length == 0)) {int perm = mService.checkComponentPermission(null,filter.receiverList.pid, filter.receiverList.uid, -1, true);if (perm != PackageManager.PERMISSION_GRANTED) {Slog.w(TAG, "Permission Denial: security check failed when receiving "+ r.intent.toString()+ " to " + filter.receiverList.app+ " (pid=" + filter.receiverList.pid+ ", uid=" + filter.receiverList.uid + ")"+ " due to sender " + r.callerPackage+ " (uid " + r.callingUid + ")");skip = true;}}if (!skip && r.appOp != AppOpsManager.OP_NONE&& mService.mAppOpsService.noteOperation(r.appOp,filter.receiverList.uid, filter.packageName)!= AppOpsManager.MODE_ALLOWED) {Slog.w(TAG, "Appop Denial: receiving "+ r.intent.toString()+ " to " + filter.receiverList.app+ " (pid=" + filter.receiverList.pid+ ", uid=" + filter.receiverList.uid + ")"+ " requires appop " + AppOpsManager.opToName(r.appOp)+ " due to sender " + r.callerPackage+ " (uid " + r.callingUid + ")");skip = true;}if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,r.callingPid, r.resolvedType, filter.receiverList.uid)) {skip = true;}if (!skip && (filter.receiverList.app == null || filter.receiverList.app.killed|| filter.receiverList.app.crashing)) {Slog.w(TAG, "Skipping deliver [" + mQueueName + "] " + r+ " to " + filter.receiverList + ": process gone or crashing");skip = true;}//即时应用检查// Ensure that broadcasts are only sent to other Instant Apps if they are marked as// visible to Instant Apps.final boolean visibleToInstantApps =(r.intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;if (!skip && !visibleToInstantApps && filter.instantApp&& filter.receiverList.uid != r.callingUid) {Slog.w(TAG, "Instant App Denial: receiving "+ r.intent.toString()+ " to " + filter.receiverList.app+ " (pid=" + filter.receiverList.pid+ ", uid=" + filter.receiverList.uid + ")"+ " due to sender " + r.callerPackage+ " (uid " + r.callingUid + ")"+ " not specifying FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS");skip = true;}if (!skip && !filter.visibleToInstantApp && r.callerInstantApp&& filter.receiverList.uid != r.callingUid) {Slog.w(TAG, "Instant App Denial: receiving "+ r.intent.toString()+ " to " + filter.receiverList.app+ " (pid=" + filter.receiverList.pid+ ", uid=" + filter.receiverList.uid + ")"+ " requires receiver be visible to instant apps"+ " due to sender " + r.callerPackage+ " (uid " + r.callingUid + ")");skip = true;}if (skip) {r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;return;}// If permissions need a review before any of the app components can run, we drop// the broadcast and if the calling app is in the foreground and the broadcast is// explicit we launch the review UI passing it a pending intent to send the skipped// broadcast.if (mService.mPermissionReviewRequired) {if (!requestStartTargetPermissionsReviewIfNeededLocked(r, filter.packageName,filter.owningUserId)) {r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;return;}}r.delivery[index] = BroadcastRecord.DELIVERY_DELIVERED;//如果是有序广播// If this is not being sent as an ordered broadcast, then we// don't want to touch the fields that keep track of the current// state of ordered broadcasts.if (ordered) {r.receiver = filter.receiverList.receiver.asBinder();r.curFilter = filter;filter.receiverList.curBroadcast = r;r.state = BroadcastRecord.CALL_IN_RECEIVE;if (filter.receiverList.app != null) {// Bump hosting application to no longer be in background// scheduling class. Note that we can't do that if there// isn't an app... but we can only be in that case for// things that directly call the IActivityManager API, which// are already core system stuff so don't matter for this.r.curApp = filter.receiverList.app;filter.receiverList.app.curReceivers.add(r);mService.updateOomAdjLocked(r.curApp, true);}}try {if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,"Delivering to " + filter + " : " + r);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 {//处理广播,见4.4节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;}} catch (RemoteException e) {Slog.w(TAG, "Failure sending broadcast " + r.intent, e);if (ordered) {r.receiver = null;r.curFilter = null;filter.receiverList.curBroadcast = null;if (filter.receiverList.app != null) {filter.receiverList.app.curReceivers.remove(r);}}}}
这里是检查动态注册的广播的相关权限,如果是有序广播则跳过。最后执行performReceiveLocked处理并行广播。
4.4 BQ.performReceiveLocked
[->BroadcastQueue.java]
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.//通过binder机制,发送到广播接收者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 {//见4.5节app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,data, extras, ordered, sticky, sendingUser, app.repProcState);// TODO: Uncomment this when (b/28322359) is fixed and we aren't getting// DeadObjectException when the process isn't actually dead.//} catch (DeadObjectException ex) {// Failed to call into the process. It's dying so just let it die and move on.// throw ex;} catch (RemoteException ex) {// Failed to call into the process. It's either dying or wedged. Kill it gently.synchronized (mService) {Slog.w(TAG, "Can't deliver broadcast to " + app.processName+ " (pid " + app.pid + "). Crashing it.");app.scheduleCrash("can't deliver broadcast");}throw ex;}} else {//应有进程死亡,则应有不存在// Application has died. Receiver doesn't exist.throw new RemoteException("app.thread must not be null");}} else {//调用者进程为空receiver.performReceive(intent, resultCode, data, extras, ordered,sticky, sendingUser);}}
通过app.thread获取到IApplicationThread代理类,通过这个代理类,访问到ApplicationThread中的方法。
4.5 AT.scheduleRegisteredReceiver
[->ActivityThread.java::ApplicationThread]
// 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);//见4.6节,其中receiver为2.3.2节所创建receiver.performReceive(intent, resultCode, dataStr, extras, ordered,sticky, sendingUser);}
receiver是注册广播时创建的,见2.3.3节 receiver=LoadedApk.ReceiverDispatcher.InnerReceiver
4.6 IR.performReceive
[->LoadedApk.java::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 (ActivityThread.DEBUG_BROADCAST) {int seq = intent.getIntExtra("seq", -1);Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction()+ " seq=" + seq + " to " + (rd != null ? rd.mReceiver : null));}if (rd != null) {//见4.7节rd.performReceive(intent, resultCode, data, extras,ordered, sticky, sendingUser);} else {// The activity manager dispatched a broadcast to a registered// receiver in this process, but before it could be delivered the// receiver was unregistered. Acknowledge the broadcast on its// behalf so that the system's broadcast sequence can continue.if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,"Finishing broadcast to unregistered receiver");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();}}}
4.7 RD.performReceive
[->LoadedApk.java::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);}}//见4.8节if (intent == null || !mActivityThread.post(args.getRunnable())) {//消息post到主线程,则不会走这里if (mRegistered && ordered) {IActivityManager mgr = ActivityManager.getService();if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,"Finishing sync broadcast to " + mReceiver);args.sendFinished(mgr);}}}
Args继承于BroadcastReceiver.PendingResult,实现了Runnable,其中mActivityThread是当前的主线程,在2.3.1节完成赋值,post消息机制,将消息放入MessageQueue,该消息是Runnable,而后执行该Runnable。
4.8 ReceiverDispatcher.Args.getRunnable
[->LoadedApk.java]
public final Runnable getRunnable() {return () -> {final BroadcastReceiver receiver = mReceiver;final boolean ordered = mOrdered;if (ActivityThread.DEBUG_BROADCAST) {int seq = mCurIntent.getIntExtra("seq", -1);Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()+ " seq=" + seq + " to " + mReceiver);Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered+ " mOrderedHint=" + ordered);}final IActivityManager mgr = ActivityManager.getService();final Intent intent = mCurIntent;if (intent == null) {Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched+ ": run() previously called at "+ Log.getStackTraceString(mPreviousRunStacktrace));}mCurIntent = null;mDispatched = true;mPreviousRunStacktrace = new Throwable("Previous stacktrace");if (receiver == null || intent == null || mForgotten) {if (mRegistered && ordered) {if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,"Finishing null broadcast to " + mReceiver);sendFinished(mgr);}return;}Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");try {//获取mReceiver的类加载器ClassLoader cl = mReceiver.getClass().getClassLoader();intent.setExtrasClassLoader(cl);intent.prepareToEnterProcess();setExtrasClassLoader(cl);receiver.setPendingResult(this);//调用receiver的onReceive回调receiver.onReceive(mContext, intent);} catch (Exception e) {if (mRegistered && ordered) {if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,"Finishing failed broadcast to " + mReceiver);sendFinished(mgr);}if (mInstrumentation == null ||!mInstrumentation.onException(mReceiver, e)) {Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);throw new RuntimeException("Error receiving broadcast " + intent+ " in " + mReceiver, e);}}if (receiver.getPendingResult() != null) {//见4.9节finish();}Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);};}
4.9 PendingResult.finish
[->BroadcastReceiver.java::PendingResult]
/* Finish the broadcast. The current result will be sent and the* next broadcast will proceed.*/public final void finish() {if (mType == TYPE_COMPONENT) {//代表静态注册的广播final IActivityManager mgr = ActivityManager.getService();if (QueuedWork.hasPendingWork()) {// If this is a broadcast component, we need to make sure any// queued work is complete before telling AM we are done, so// we don't have our process killed before that. We now know// there is pending work; put another piece of work at the end// of the list to finish the broadcast, so we don't block this// thread (which may be the main thread) to have it finished.//// Note that we don't need to use QueuedWork.addFinisher() with the// runnable, since we know the AM is waiting for us until the// executor gets to it.QueuedWork.queue(new Runnable() {@Override public void run() {if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,"Finishing broadcast after work to component " + mToken);sendFinished(mgr);//见4.9.1节}}, false);} else {if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,"Finishing broadcast to component " + mToken);sendFinished(mgr);//见4.9.1节}} else if (mOrderedHint && mType != TYPE_UNREGISTERED) { //动态注册的串行广播if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,"Finishing broadcast to " + mToken);final IActivityManager mgr = ActivityManager.getService();sendFinished(mgr);//见4.9.1节}}
主要工作:
1.静态注册的广播接收者:
-
当QueuedWork工作未完成时,则等待完成再执行sendFinished
-
当QueuedWork工作已经完成,直接调用sendFinished方法
2.动态注册的广播接收者:当发送的是串行广播,则直接调用sendFinished
参数说明:
TYPE_COMPONENT:静态注册
TYPE_REGISTERED:动态注册
TYPE_UNREGISTERED:取消注册
4.9.1 PendingResult.sendFinished
[->BroadcastReceiver.java::PendingResult]
/** @hide */public void sendFinished(IActivityManager am) {synchronized (this) {if (mFinished) {throw new IllegalStateException("Broadcast already finished");}mFinished = true;try {if (mResultExtras != null) {mResultExtras.setAllowFds(false);}//串行广播,见4.9.2if (mOrderedHint) {am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,mAbortBroadcast, mFlags);} else {// 并行广播,当属于静态注册的广播,需要告知AMS// This broadcast was sent to a component; it is not ordered,// but we still need to tell the activity manager we are done.am.finishReceiver(mToken, 0, null, null, false, mFlags);}} catch (RemoteException ex) {}}}
4.9.2 AMS.finishReceiver
[->ActivityManagerService.java]
通过binder机制最后调用到AMS的finishReceiver方法。
public void finishReceiver(IBinder who, int resultCode, String resultData,Bundle resultExtras, boolean resultAbort, int flags) {if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + who);// Refuse possible leaked file descriptorsif (resultExtras != null && resultExtras.hasFileDescriptors()) {throw new IllegalArgumentException("File descriptors passed in Bundle");}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) {//见4.9.3节doNext = r.queue.finishReceiverLocked(r, resultCode,resultData, resultExtras, resultAbort, true);}if (doNext) {//处理下一条广播r.queue.processNextBroadcastLocked(/*fromMsg=*/ false, /*skipOomAdj=*/ true);}// updateOomAdjLocked() will be done heretrimApplicationsLocked();}} finally {Binder.restoreCallingIdentity(origId);}}
4.9.3 BQ.finishReceiverLocked
[->BroadcastQueue.java]
public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {final int state = r.state;final ActivityInfo receiver = r.curReceiver;r.state = BroadcastRecord.IDLE;if (state == BroadcastRecord.IDLE) {Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");}r.receiver = null;r.intent.setComponent(null);if (r.curApp != null && r.curApp.curReceivers.contains(r)) {r.curApp.curReceivers.remove(r);}if (r.curFilter != null) {r.curFilter.receiverList.curBroadcast = null;}r.curFilter = null;r.curReceiver = null;r.curApp = null;mPendingBroadcast = null;r.resultCode = resultCode;r.resultData = resultData;r.resultExtras = resultExtras;if (resultAbort && (r.intent.getFlags()&Intent.FLAG_RECEIVER_NO_ABORT) == 0) {r.resultAbort = resultAbort;} else {r.resultAbort = false;}if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices&& r.queue.mOrderedBroadcasts.size() > 0&& r.queue.mOrderedBroadcasts.get(0) == r) {ActivityInfo nextReceiver;if (r.nextReceiver < r.receivers.size()) {Object obj = r.receivers.get(r.nextReceiver);nextReceiver = (obj instanceof ActivityInfo) ? (ActivityInfo)obj : null;} else {nextReceiver = null;}// Don't do this if the next receive is in the same process as the current one.if (receiver == null || nextReceiver == null|| receiver.applicationInfo.uid != nextReceiver.applicationInfo.uid|| !receiver.processName.equals(nextReceiver.processName)) {// In this case, we are ready to process the next receiver for the current broadcast,// but are on a queue that would like to wait for services to finish before moving// on. If there are background services currently starting, then we will go into a// special state where we hold off on continuing this broadcast until they are done.if (mService.mServices.hasBackgroundServicesLocked(r.userId)) {Slog.i(TAG, "Delay finish: " + r.curComponent.flattenToShortString());r.state = BroadcastRecord.WAITING_SERVICES;return false;}}}r.curComponent = null;// We will process the next receiver right now if this is finishing// an app receiver (which is always asynchronous) or after we have// come back from calling a receiver.return state == BroadcastRecord.APP_RECEIVE|| state == BroadcastRecord.CALL_DONE_RECEIVE;}
这个过程主要是设置BroadcastRecord各个参数为null,并判断是否还有广播需要处理。
4.10 小结
接收广播的过程,主要是对并行广播队列和串行广播队列的处理,先处理并行广播队列后处理串行广播队列:
1.处理广播队列,对广播队列进行相应的权限检查处理。无论是并行还是串行,最后调用的都是performReceiveLocked方法。其中串行广播还有时间限制,会调用broadcastTimeoutLocked方法,超时会强制结束广播;
2.通过Binder机制,将消息传递给接收广播的进程进行处理,如果接收广播的进程没起来,还需要启动其进程;
3.最后回调receiver.onReceive的方法,对于串行广播还需要通知AMS已经处理完该条广播,并进行下个广播的处理。
五、总结
发送广播过程的流程如下:
1.当发送串行广播(order= true)时
-
静态注册的广播接收者(receivers),采用串行处理
-
动态注册的广播接收者(registeredReceivers),采用串行处理
2.当发送并行广播(order= false)时
-
静态注册的广播接收者(receivers),采用串行处理
-
动态注册的广播接收者(registeredReceivers),采用并行处理
静态注册的receiver都是采用串行处理;动态注册的registeredReceivers处理方式无论是串行还是并行,取决于广播的发送方式(processNextBroadcast);静态注册的广播由于其所在的进程没有创建,而进程的创建需要耗费系统的资源比较多,所以让静态注册的广播串行化,防止瞬间启动大量的进程。
广播ANR只有在串行广播时才需要考虑,因为接收者是串行处理的,前一个receiver处理慢,会影响后一个receiver;并行广播通过一个循环一次性将所有的receiver分发完,不存在彼此影响的问题,没有广播超时。
串行超时情况:某个广播处理时间>2receiver总个数mTimeoutPeriod,其中mTimeoutPeriod,前后队列为10s,后台队列为60s;某个receiver的执行时间超过mTimeoutPeriod。
附录
源码路径
frameworks/base/services/core/java/com/android/server/am/BroadcastRecord.java
frameworks/base/core/java/android/app/ContextImpl.java
frameworks/base/core/java/android/app/LoadedApk.java
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks/base/core/java/android/content/IntentFilter.java
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
frameworks/base/core/java/android/content/BroadcastReceiver.java