行业知识
Android13 广播发送流程分析
一、广播相关概念
广播分类
1、标准广播:异步广播,广播发出后,所有注册了的广播接收器都会同时接收到该广播。打个比方:做地铁过程中的语音播报,当列车员(广播发出者)进行语音播报(发送广播)时,所有乘客(注册接收该广播的程序)都可以同时听到语音,不分先后顺序。
sendBroadcast();
2、有序广播:同步发送,广播发出后,按照注册了的广播接收器的优先级顺序广播,优先级的范围是-1000~1000,数字越大,优先级越高,最先接收到该广播,接收器的优先级通过android:priority设置,并且先收到广播的可以修改或者抛弃该广播,后面优先级小的接收器就无法收到了。同级别的广播,动态优先于静态;同级别同类型的广播,静态:先扫描的优先于后扫描的,动态:先注册的优先于后注册的。
sendOrderedBroadcast();
3、粘性广播:粘性广播的机制就是发送广播的时候如果没有找到接收器,就会先保存下来,等有广播接收器注册的时候,再把之前保存的广播发出去。因为从Android 5.0(API 21)开始,因为安全性的问题,官方已经正式废弃了粘性广播。
sendStickyBroadcast();
广播注册方式
1、动态注册:在Context(即Service或Activity)组件中注册,通过registerReceiver()方法注册,在不使用时取消注册unregisterReceiver()。如果广播发送的时候注册Broadcast的组件没有启动的话,是收不到广播的。
2、 静态注册:在AndroidManifest.xml中注册,并在intent-filter中添加响应的action,并新建一个Broadcast组件类来处理注册广播。如果广播发送的时候Broadcast的组件类进程没有启动的话,会收到广播并启动进程。
具体实现可参考Android的有序广播和无序广播(解决安卓8.0版本之后有序广播的接收问题) 区分了Android8.0前后的实现方式。
前台广播及后台广播
前台广播:在广播发送的时候添加Intent.FLAG_RECEIVER_FOREGROUND flag。
后台广播:在广播发送的时候没有Intent.FLAG_RECEIVER_FOREGROUND flag。
默认情况下,Intent是不带Intent.FLAG_RECEIVER_FOREGROUND 的flag的,所以我们默认使用的都是后台广播。
二、广播发送流程
1、调用ContextImpl的sendBroadcast发送广播
frameworks/base/core/java/android/app/ContextImpl.java
@Override public void sendBroadcast(Intent intent) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { //准备离开现有进程 intent.prepareToLeaveProcess(this); //调用 AMS 的broadcastIntentWithFeature方法 ActivityManager.getService().broadcastIntentWithFeature( mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, false/**表示非有序**/, false/**表示非粘性**/, getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } 2、调用AMS的broadcastIntentWithFeature方法
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@Override public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, String[] excludedPermissions, String[] excludedPackages, int appOp, Bundle bOptions, boolean serialized, boolean sticky, int userId) { enforceNotIsolatedCaller("broadcastIntent"); synchronized(this) { // 验证广播的有效性 intent = verifyBroadcastLocked(intent); final ProcessRecord callerApp = getRecordForAppLOSP(caller); final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); //保留原始的origId final long origId = Binder.clearCallingIdentity(); /// M: DuraSpeed @{ String suppressAction = mAmsExt.onReadyToStartComponent( callerApp != null ? callerApp.info.packageName : null, callingUid, "broadcast", null); if ((suppressAction != null) && suppressAction.equals("skipped")) { Binder.restoreCallingIdentity(origId); Slog.d(TAG, "broadcastIntentWithFeature, suppress to broadcastIntent!"); return ActivityManager.BROADCAST_SUCCESS; } /// @} try { return broadcastIntentLocked(callerApp, callerApp != null ? callerApp.info.packageName : null, callingFeatureId, intent, resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions, excludedPermissions, excludedPackages, appOp, bOptions, serialized, sticky, callingPid, callingUid, callingUid, callingPid, userId); } finally { //恢复origId Binder.restoreCallingIdentity(origId); } } } 单独罗列 verifyBroadcastLocked 方法:
final Intent verifyBroadcastLocked(Intent intent) { // Refuse possible leaked file descriptors // 拒绝存在有文件描述符的intent if (intent != null && intent.hasFileDescriptors() == true) { throw new IllegalArgumentException("File descriptors passed in Intent"); } int flags = intent.getFlags(); if (!mProcessesReady) { //系统还没有准备好,表示还没有调用systemReady 函数. // if the caller really truly claims to know what they're doing, go // ahead and allow the broadcast without launching any receivers if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) { //包含Intent.FLAG_RECEIVER_REGISTERED_ONLY的flag,可以继续往下走. // This will be turned into a FLAG_RECEIVER_REGISTERED_ONLY later on if needed. } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent + " before boot completion"); throw new IllegalStateException("Cannot broadcast before boot completed"); } } if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) { //禁止携带Intent.FLAG_RECEIVER_BOOT_UPGRADE flag throw new IllegalArgumentException( "Can't use FLAG_RECEIVER_BOOT_UPGRADE here"); } if ((flags & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) { switch (Binder.getCallingUid()) { case ROOT_UID: case SHELL_UID: break; default:// 若不是ROOT和SHELL用户,则移除 Intent.FLAG_RECEIVER_FROM_SHELL flag Slog.w(TAG, "Removing FLAG_RECEIVER_FROM_SHELL because caller is UID " + Binder.getCallingUid()); intent.removeFlags(Intent.FLAG_RECEIVER_FROM_SHELL); break; } } return intent; } 单独罗列 getRecordForAppLOSP 方法:
@GuardedBy(anyOf = {"this", "mProcLock"}) ProcessRecord getRecordForAppLOSP(IApplicationThread thread) { if (thread == null) { return null; } ProcessRecord record = mProcessList.getLRURecordForAppLOSP(thread); if (record != null) return record; // 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 pmap = mProcessList.getProcessNamesLOSP().getMap(); for (int i = pmap.size()-1; i >= 0; i--) { final SparseArray procs = pmap.valueAt(i); for (int j = procs.size()-1; j >= 0; j--) { final ProcessRecord proc = procs.valueAt(j); final IApplicationThread procThread = proc.getThread(); if (procThread != null && procThread.asBinder() == threadBinder) { Slog.wtf(TAG, "getRecordForApp: exists in name list but not in LRU list: " + proc); return proc; } } } return null; } 3、调用AMS的broadcastIntentLocked方法
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java3.1 系统广播处理broadcastIntentLocked
@GuardedBy("this") final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, @Nullable String callerFeatureId, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, String[] excludedPermissions, String[] excludedPackages, int appOp, Bundle bOptions, boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid, int realCallingPid, int userId, boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken, @Nullable int[] broadcastAllowList) { intent = new Intent(intent); //判断是InstantApp final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid); // Instant Apps cannot use FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS if (callerInstantApp) { //取消FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS flag标记 intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); } if (userId == UserHandle.USER_ALL && broadcastAllowList != null) { Slog.e(TAG, "broadcastAllowList only applies when sending to inpidual users. " + "Assuming restrictive whitelist."); // userId是USER_ALL ,则不需要此限制. broadcastAllowList = new int[]{}; } // 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 + " userBroadcast " + 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; } } final String action = intent.getAction(); BroadcastOptions brOptions = null; if (bOptions != null) { brOptions = new BroadcastOptions(bOptions); if (brOptions.getTemporaryAppAllowlistDuration() > 0) { // 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(CHANGE_DEVICE_IDLE_TEMP_WHITELIST, realCallingPid, realCallingUid, -1, true) != PackageManager.PERMISSION_GRANTED && checkComponentPermission(START_ACTIVITIES_FROM_BACKGROUND, realCallingPid, realCallingUid, -1, true) != PackageManager.PERMISSION_GRANTED && checkComponentPermission(START_FOREGROUND_SERVICES_FROM_BACKGROUND, realCallingPid, realCallingUid, -1, true) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: " + intent.getAction() + " broadcast from " + callerPackage + " (p, u)" + " requires " + CHANGE_DEVICE_IDLE_TEMP_WHITELIST + " or " + START_ACTIVITIES_FROM_BACKGROUND + " or " + START_FOREGROUND_SERVICES_FROM_BACKGROUND; Slog.w(TAG, msg); throw new SecurityException(msg); } } // 不能发送给受限的应用 if (brOptions.isDontSendToRestrictedApps() && !isUidActiveLOSP(callingUid) && isBackgroundRestrictedNoCheck(callingUid, callerPackage)) { Slog.i(TAG, "Not sending broadcast " + action + " - app " + callerPackage + " has background restrictions"); return ActivityManager.START_CANCELED; } if (brOptions.allowsBackgroundActivityStarts()) { // 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.START_ACTIVITIES_FROM_BACKGROUND, realCallingPid, realCallingUid, -1, true) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: " + intent.getAction() + " broadcast from " + callerPackage + " (p, u)" + " requires " + android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; Slog.w(TAG, msg); throw new SecurityException(msg); } else { allowBackgroundActivityStarts = true; // We set the token to null since if it wasn't for it we'd allow anyway here backgroundActivityStartsToken = null; } } } // 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: //TINNO BEGIN //DATE20221208, Modify By XIBIN,DGF-1148 isCallerSystem = (callerApp != null) && callerApp.isPersistent() ||("com.android.systemui".equals(callerPackage) && "com.android.settings.flashlight.action.FLASHLIGHT_CHANGED".equals(action)); //TINNO END 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 p, uPermission 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. //对于ACTION_APPWIDGET_CONFIGURE和ACTION_APPWIDGET_UPDATE 了,两个action,需要调用着和显式组件的包名保持一致. 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); } } } boolean timeoutExempt = false; if (action != null) { //判断是否属于豁免的广播. if (getBackgroundLaunchBroadcasts().contains(action)) { if (DEBUG_BACKGROUND_CHECK) { Slog.i(TAG, "Broadcast action " + action + " forcing include-background"); } //增加background 应用接收. intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); } switch (action) { case Intent.ACTION_UID_REMOVED: case Intent.ACTION_PACKAGE_REMOVED: case Intent.ACTION_PACKAGE_CHANGED: case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE: case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE: case Intent.ACTION_PACKAGES_SUSPENDED: case Intent.ACTION_PACKAGES_UNSUSPENDED: // 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 + " (p, u)" + " 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); if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { mAppOpsService.resetAllModes(UserHandle.getUserId(uid), intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME)); } else { 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); //将可以用的应用进行force stop if (list != null && list.length > 0) { for (int i = 0; i 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"); } // 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 stickies = mStickyBroadcasts.get( UserHandle.USER_ALL); if (stickies != null) { ArrayList list = stickies.get(intent.getAction()); if (list != null) { int N = list.size(); int i; for (i=0; i= stickiesCount) { list.add(new Intent(intent)); } } int[] 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 registeredReceivers = null; // Need to resolve the intent to interested receivers... if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { //在PMS中去查询对应的广播接收者,获取静态广播接受者的列表 receivers = collectReceiverComponents( intent, resolvedType, callingUid, users, broadcastAllowList); } if (intent.getComponent() == null) { //若不指定广播接收者.则会遍历所有符合条件的接收者 if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) { // Query one target user at a time, excluding shell-restricted users for (int i = 0; i = 0; i--) { final int owningAppId = UserHandle.getAppId(registeredReceivers.get(i).owningUid); if (owningAppId >= Process.FIRST_APPLICATION_UID && Arrays.binarySearch(broadcastAllowList, owningAppId) 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) { //对应system的调用者进行验证 checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid, isProtectedBroadcast, registeredReceivers); } final BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType, requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId, allowBackgroundActivityStarts, backgroundActivityStartsToken, timeoutExempt); 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) { //若不进行旧的广播替换,则开始加入队列进行并行分发. queue.enqueueParallelBroadcastLocked(r); //安排广播分发 queue.scheduleBroadcastsLocked(); } //表示处理完成,则将动态广播接收者进行清空. registeredReceivers = null; NR = 0; } // 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. //过滤ACTION_PACKAGE_ADDED , ACTION_PACKAGE_RESTARTED 和ACTION_PACKAGE_DATA_CLEARED 对应包名 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); } if (skipPackages != null && (skipPackages.length > 0)) { for (String skipPackage : skipPackages) { if (skipPackage != null) { int NT = receivers.size(); for (int it=0; it= 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; } } } //将所有的动态广播插入final receivers 中 while (ir 0) || resultTo != null) { // BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType, requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions, receivers, resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId, allowBackgroundActivityStarts, backgroundActivityStartsToken, timeoutExempt); if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r); 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 { //若替代的广播,则更新old的队列 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 { //分发有序广播 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); } } return ActivityManager.BROADCAST_SUCCESS; } 小结:
(1) 对粘性广播的处理过程。把粘性广播放在了list列表中,而list以action为键放置在了stickies中,而stickies又以userId为键放在了mStickyBroadcasts中,因此mStickyBroadcasts保存了设备中所有用户粘性广播的Intent相关信息。
(2)静态和动态注册的接收器
[1] 上面这段代码主要是获取静态和动态注册的接收器。其中receivers 表示静态注册接收器列表, registeredReceivers 表示动态注册接收器列表;
[2] Intent.FLAG_RECEIVER_REGISTERED_ONLY该flag表示仅支持动态注册,不支持静态注册,如果在manifest中注册是收不到该广播的;
[3] 如果发送广播不加Component信息会遍历获取所有的当前intent的接收者,因此如果定向发给某个应用的话,要把Component信息加上。
(3) 无序动态注册接收器添加到并发列表中
[1] 上面这段代码是,如果发送的是无序广播,且存在动态注册的广播接收者,就将该广播加入并行处理队列,并进行一次广播发送。简单来说就是【动态注册且接受无序广播的广播接收者】是并行操作,广播发送速度会比较快。
[2] Intent.FLAG_RECEIVER_REPLACE_PENDING 该flag表示是否替换待发出的广播,如果flag为1会进行替换, 位置与待发广播一样。
(4)合并有序动态注册和静态注册接收器
[1] 上面这段代码主要是对【动态注册接受有序广播的广播接收者】和【静态注册的广播接收者】进行合并,如果是有序广播,动态接收者和静态的接收者合并到一个队列里面进行处理,也就是说order广播下,所有的接收者(静态和动态)处理方式都是一样的,都是串行处理;
[2] 对于静态注册的接收者而言,始终是和order广播的处理方式是一样的,也就是说静态的接收者只有order模式(串行化接收);
[3] 在合并过程中,如果一个动态注册的广播接收者和一个静态注册的目标广播接收者的优先级相同,那么动态注册的目标接收者会排在静态注册的目标广播接收者前面,即动态注册的目标广播接收者会优先于静态注册的广播接收者接收到有序广播。
(5)系统广播处理broadcastIntentLocked函数这部分代码逻辑总结:首先是判断是不是系统广播,也就是switch语句中的部分,这部分的广播是系统发出的,根据不同广播做出不同的处理,系统广播我们可以接收但是不能发送,只能由系统发出;接着是粘性广播的处理;然后是【动态注册且接受无序广播的广播接收者】的处理,把他们放入到BroadcastQueue的mParallelBroadcasts中,并调用scheduleBroadcastsLocked,BroadcastQueue对mParallelBroadcasts列表中条目的最终处理是通过并行操作来完成的;最后是【动态注册接受有序广播的广播接收者】和【静态注册的广播接收者】的处理,把他们放入到BroadcastQueue的mOrderedBroadcasts中,并调用scheduleBroadcastsLocked,BroadcastQueue对mOrderedBroadcasts列表中条目的最终处理是通过串行操作来完成的;
4、BroadcastQueue广播处理
4.1 BroadcastQueue队列定义及入队列方法判断
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
/** * Lists of all active broadcasts that are to be executed immediately * (without waiting for another broadcast to finish). Currently this only * contains broadcasts to registered receivers, to avoid spinning up * a bunch of processes to execute IntentReceiver components. Background- * and foreground-priority broadcasts are queued separately. */ final ArrayList mParallelBroadcasts = new ArrayList();
/** * Tracking of the ordered broadcast queue, including deferral policy and alarm * prioritization. */ final BroadcastDispatcher mDispatcher;
在广播队列中定义了两个处理列表,一个是并发处理列表mParallelBroadcasts,一个是有序处理列表mDispatcher。
BroadcastQueue broadcastQueueForIntent(Intent intent) { if (isOnOffloadQueue(intent.getFlags())) { if (DEBUG_BROADCAST_BACKGROUND) { Slog.i(TAG_BROADCAST, "Broadcast intent " + intent + " on offload queue"); } return mOffloadBroadcastQueue; } 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; } public void enqueueParallelBroadcastLocked(BroadcastRecord r) { mParallelBroadcasts.add(r); enqueueBroadcastHelper(r); } public void enqueueOrderedBroadcastLocked(BroadcastRecord r) { mDispatcher.enqueueOrderedBroadcastLocked(r); enqueueBroadcastHelper(r); } 上面的三个方法是上面源码中出现的,broadcastQueueForIntent根据intent是否含有Intent.FLAG_RECEIVER_FOREGROUND来判断是前台广播还是普通后台广播,如果是前台广播返回前台广播处队列。如果是普通后台广播返回后台广播处理队列。
获取队列后,将发给【动态注册且接受无序广播的广播接收者】的广播通过enqueueParallelBroadcastLocked函数添加到该队列的并发处理列表中。将发给【动态注册接受有序广播的广播接收者】和【静态注册的广播接收者】的广播通过enqueueOrderedBroadcastLocked函数添加到该队列的有序处理列表中。
4.2 BroadcastQueue队列中广播发送流程
从上面的源码分析中看到最后我们都执行了scheduleBroadcastsLocked对广播进行了进一步发送处理,接下来看下这个函数的逻辑。
public void scheduleBroadcastsLocked() { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts [" + mQueueName + "]: current=" + mBroadcastsScheduled); if (mBroadcastsScheduled) { //若正在调度中,则取消本地调度 return; } mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this)); mBroadcastsScheduled = true; } private final class BroadcastHandler extends Handler { public BroadcastHandler(Looper looper) { super(looper, null, true); } @Override public void handleMessage(Message msg) { switch (msg.what) { case BROADCAST_INTENT_MSG: { if (DEBUG_BROADCAST) Slog.v( TAG_BROADCAST, "Received BROADCAST_INTENT_MSG [" + mQueueName + "]"); //开始处理广播 processNextBroadcast(true); } break; case BROADCAST_TIMEOUT_MSG: { synchronized (mService) { broadcastTimeoutLocked(true); } } break; } } } 先判断mBroadcastsScheduled的值,如果true说明消息队列已经存在一个类型为BROADCAST_INTENT_MSG的消息了,直接返回,因为该消息在执行完毕会自动调用下一条消息;
接下来广播的处理逻辑会走到 processNextBroadcast函数中,下面来看下该函数的逻辑。
private void processNextBroadcast(boolean fromMsg) { synchronized (mService) { processNextBroadcastLocked(fromMsg, false); } } 详细分析 processNextBroadcastLocked 函数:
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) { BroadcastRecord r; if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast [" + mQueueName + "]: " + mParallelBroadcasts.size() + " parallel broadcasts; " + mDispatcher.describeStateLocked()); //更新CPU统计信息 mService.updateCpuStats(); if (fromMsg) { //来自于BROADCAST_INTENT_MSG, 说明广播已经在处理,可以将此变量标记为false mBroadcastsScheduled = false; } // First, deliver any non-serialized broadcasts right away. // 无序广播之间不存在相互等待,这里处理的是保存在无序广播调度队列mParallelBroadcasts中的广播发送任务, // 即把保存在无序广播调度队列mParallelBroadcasts中的广播发送给它的目标广播接收者处理 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
下一篇:开心农场服务器怎么连不上?