您好,登錄后才能下訂單哦!
今天小編給大家分享一下ActivityManagerService廣播怎么注冊與發送的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
廣播接收器可以分為動態和靜態,靜態廣播接收器就是在 AndroidManifest.xml 中注冊的,而動態的廣播接收器是在代碼中通過 Context#registerReceiver() 注冊的。
靜態廣播接收器,在發送廣播時,服務端會從 PKMS 中收集,而動態的廣播接收器,需要接收方發送給服務端。因此,下面只分析動態廣播接收器的注冊過程
// ContextImpl.java public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user, IntentFilter filter, String broadcastPermission, Handler scheduler) { return registerReceiverInternal(receiver, user.getIdentifier(), filter, broadcastPermission, scheduler, getOuterContext(), 0); } 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) { // 默認主線程 Handler if (scheduler == null) { scheduler = mMainThread.getHandler(); } // 1. 獲取 IIntentReceiver 對象 // 其實這里獲取的就是一個 Binder 對象,用于注冊給 AMS,從而接收廣播信息的回調 rd = mPackageInfo.getReceiverDispatcher( receiver, context, scheduler, mMainThread.getInstrumentation(), true); } else { // ... } } try { // 2. 向 AMS 注冊 IIntentReceiver final Intent intent = ActivityManager.getService().registerReceiverWithFeature( mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(), AppOpsManager.toReceiverId(receiver), rd, filter, broadcastPermission, userId, flags); if (intent != null) { intent.setExtrasClassLoader(getClassLoader()); intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent), getAttributionSource()); } return intent; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
廣播接收方注冊接收器的過程如下
獲取 IIntentReceiver 對象,它是一個 Binder 對象,其實就是一個 Binder 回調。
向服務端 AMS 注冊 IIntentReceiver 對象,用于接收廣播消息的回調。
當接收方收到來自服務端的廣播消息后,會通過 IIntentReceiver 對象,調用 BroadcastReceiver#onReceive() 來處理廣播。
現在來看下服務端是如何完成廣播接收器的注冊工作的
// AcitityManagerService.java public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage, String callerFeatureId, String receiverId, 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) { // 確保接收方進程存在,并該進程的 uid 和 pid if (caller != null) { callerApp = getRecordForAppLOSP(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.getPkgList().containsKey(callerPackage) && !"android".equals(callerPackage)) { throw new SecurityException("Given caller package " + callerPackage + " is not running in process " + callerApp); } callingUid = callerApp.info.uid; callingPid = callerApp.getPid(); } 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); Iterator<String> actions = filter.actionsIterator(); if (actions == null) { ArrayList<String> noAction = new ArrayList<String>(1); noAction.add(null); actions = noAction.iterator(); } // Collect stickies of users int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) }; // 遍歷 IntentFilter 保存的所有 action,匹配相應的 sticky 廣播,并保存到 stickyIntents // 從這里可以看出,可以先發送 sticky 廣播,然后再注冊 sticky 廣播接收器 while (actions.hasNext()) { String action = actions.next(); for (int id : userIds) { ArrayMap<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>(); } stickyIntents.addAll(intents); } } } } } // 剛才是用 action 匹配 sticky 廣播,現在使用 IntentFilter 再次過濾 // 過濾后的 sticky 廣播 ,保存到 allSticky // 因此 allSticky 保存的才是最終完美匹配到的 sticky 廣播 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; } // 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>(); } allSticky.add(intent); } } } // The first sticky in the list is returned directly back to the client. // 從這里可以看出,如果注冊的廣播接收器為 null,那么表示要獲取最近一次 sticky 廣播的數據 Intent sticky = allSticky != null ? allSticky.get(0) : null; if (receiver == null) { return sticky; } // ... synchronized (this) { IApplicationThread thread; // 注意學會這里的操作,如何判斷原來的進程已經死亡 if (callerApp != null && ((thread = callerApp.getThread()) == null || thread.asBinder() != caller.asBinder())) { // Original caller already died return null; } // 1. mRegisteredReceivers 建立客戶端與服務端的廣播接收器的映射 // 客戶端注冊的廣播接收器是 IIntentReceiver, 而服務端的是 ReceiverList ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder()); if (rl == null) { rl = new ReceiverList(this, callerApp, callingPid, callingUid, userId, receiver); if (rl.app != null) { final int totalReceiversForApp = rl.app.mReceivers.numberOfReceivers(); if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) { throw new IllegalStateException("Too many receivers, total of " + totalReceiversForApp + ", registered for pid: " + rl.pid + ", callerPackage: " + callerPackage); } // ProcessRecord#mReceivers 保存 ReceiverList rl.app.mReceivers.addReceiver(rl); } else { // ... } mRegisteredReceivers.put(receiver.asBinder(), rl); } else { // ... } // 2. 創建服務端的廣播過濾器 BroadcastFilter,并保存到 mReceiverResolver BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId, receiverId, 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 { // ReceiverList 是 ArrayList 子類,之所以用一個列表保存 BroadcastFilter // 是因為在注冊廣播接收器時,可以為同一個廣播接收器匹配多個過濾器 rl.add(bf); if (!bf.debugCheck()) { Slog.w(TAG, "==> For Dynamic broadcast"); } // 解析過濾器的數據,然后用相應的數據結構保存 mReceiverResolver.addFilter(bf); } // Enqueue broadcasts for all existing stickies that match // this filter. // 注意,這里處理的情況是,注冊的 sticky 廣播接收器不為 null // 那么把匹配到的 sticky 廣播,發送給這個廣播接收器 // 是不是非常有意思,注冊 sticky 廣播接收器,就能立即收到廣播,這得益于 sticky 廣播被緩存 if (allSticky != null) { // 很奇怪,BroadcastFilter 怎么是廣播接收器呢? ArrayList receivers = new ArrayList(); receivers.add(bf); final int stickyCount = allSticky.size(); for (int i = 0; i < stickyCount; i++) { Intent intent = allSticky.get(i); BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, null, null, null, -1, -1, false, null, null, null, OP_NONE, null, receivers, null, 0, null, null, false, true, true, -1, false, null, false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */); queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } } return sticky; } }
服務端對于動態注冊的廣播接收器的處理過程如下
使用 mRegisteredReceivers 建立客戶端與服務端的廣播接收器的映射。ReceiverList 代表服務端的廣播接收器,IIntentReceiver 代表客戶端的廣播接收器。
使用客戶端的 IntentFilter , 創建服務端的廣播過濾器 BroadcastFilter,并保存到 mReceiverResolver。注意,這一步中,ReceiverList 和 BroadcastFilter 互相保存了引用。
這些數據結構都是相互關聯的,有何種用意呢?當發送方發送廣播到 AMS,AMS 會使用 mReceiverResolver 匹配 BroadcastFilter,BroadcastFilter 找到 ReceiverList,ReceiverList 找到 IIntentReceiver,IIntentReceiver 發送廣播給接收方。
另外,由于 sticky 廣播是會被緩存的,當注冊 sticky 廣播的接收器時,有以下兩種處理方式
如果注冊的廣播接收器為 null,那么會返回最近的一次廣播數據給接收方。
如果注冊的廣播接收器不為null,那么會把匹配到的 sticky 廣播發送給接收方的廣播接收器,也就是會調用 BroadcastReceiver#onReceive()。
發送廣播的方法,有多個重載方法,挑選一個最簡單的來分析,如下
// ContextImpl.java public void sendBroadcast(Intent intent) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(this); 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(); } }
// ActivityManagerService.java 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(); final long origId = Binder.clearCallingIdentity(); 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 { Binder.restoreCallingIdentity(origId); } } } final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, 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) { return broadcastIntentLocked(callerApp, callerPackage, callerFeatureId, intent, resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions, excludedPermissions, excludedPackages, appOp, bOptions, ordered, sticky, callingPid, callingUid, realCallingUid, realCallingPid, userId, false /* allowBackgroundActivityStarts */, null /* tokenNeededForBackgroundActivityStarts */, null /* broadcastAllowList */); } 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,防止原始 intent 數據被修改 intent = new Intent(intent); // ... // If we have not finished booting, don't allow this to launch new processes. // AMS 還沒有啟動完成前,廣播只能發送給動態注冊的廣播接收器,這樣可以防止拉起新的進程 if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); } // ... final String action = intent.getAction(); BroadcastOptions brOptions = null; // bOptions 可以解決發送廣播的一些限制,例如從后臺啟動Activity,只有系統 app 才能用到的 API if (bOptions != null) { // ... } // 限制受保護的廣播,只能由系統代碼發送 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.isPersistent(); break; } 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)) { // ... } } boolean timeoutExempt = false; if (action != null) { // 如果系統配置文件中允許發送這個后臺廣播,那么添加 Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND 標志位 // 例如 frameworks/base/data/etc/framework-sysconfig.xml 允許發送如下后臺廣播 // <allow-implicit-broadcast action="android.intent.action.SIM_STATE_CHANGED" /> if (getBackgroundLaunchBroadcasts().contains(action)) { if (DEBUG_BACKGROUND_CHECK) { Slog.i(TAG, "Broadcast action " + action + " forcing include-background"); } intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); } switch (action) { // 對一些特殊的廣播進行處理... } } // 1. 緩存 sticky 廣播到 mStickyBroadcasts if (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"); } // 確保使用 userId 發送的 sticky 廣播,不會與使用 USER_ALL 發送的 sticky 廣播有沖突 if (userId != UserHandle.USER_ALL) { ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get( UserHandle.USER_ALL); if (stickies != null) { ArrayList<Intent> list = stickies.get(intent.getAction()); if (list != null) { int N = list.size(); int i; for (i=0; i<N; i++) { if (intent.filterEquals(list.get(i))) { throw new IllegalArgumentException( "Sticky broadcast " + intent + " for user " + userId + " conflicts with existing global broadcast"); } } } } } // 獲取 userId 對應的 sticky 廣播緩存,并把這個stikcy廣播添加/替換到緩存中 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)); } } int[] users; if (userId == UserHandle.USER_ALL) { // 如果以 USER_ALL 名字發送,那么獲取所有的啟動的 user users = mUserController.getStartedUserArray(); } else { users = new int[] {userId}; } // Figure out who all will receive this broadcast. // 現在開始找出誰需要接收這個廣播 List receivers = null; List<BroadcastFilter> registeredReceivers = null; // 2. 收集動態和靜態廣播接收器 // Intent.FLAG_RECEIVER_REGISTERED_ONLY 表示廣播只能發送給動態注冊的廣播接收器 // 沒有指定這個標志位,那么就需要收集靜態注冊的廣播接收器 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { // receivers 此時保存的是靜態廣播接收器 receivers = collectReceiverComponents( intent, resolvedType, callingUid, users, broadcastAllowList); } if (intent.getComponent() == null) { if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) { // ...以 USER_ALL 身份,從 shell 發送的廣播,那么需要獲取所有用戶注冊的廣播接收器 } else { // 收集單個用戶注冊的動態廣播接收器 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, userId); } } // 是否替換即將發送的廣播 final boolean replacePending = (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0; if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing broadcast: " + intent.getAction() + " replacePending=" + replacePending); // broadcastAllowList 是能接收廣播 app 白名單 // 如果收集的動態注冊的廣播接收器,不屬于白名單中的 app,那么移除它 if (registeredReceivers != null && broadcastAllowList != null) { for (int i = registeredReceivers.size() - 1; i >= 0; i--) { final int owningAppId = UserHandle.getAppId(registeredReceivers.get(i).owningUid); if (owningAppId >= Process.FIRST_APPLICATION_UID && Arrays.binarySearch(broadcastAllowList, owningAppId) < 0) { registeredReceivers.remove(i); } } } // 3. 對于非有序廣播(包括sticky廣播),先"并行"地發送給動態廣播接收器 int NR = registeredReceivers != null ? registeredReceivers.size() : 0; if (!ordered && NR > 0) { if (isCallerSystem) { 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 NR = 0; } // 4. 對于有序廣播,按照優先級從高到低的順序,合并靜態和動態廣播接收器到 receivers int ir = 0; // receivers 收集的是靜態注冊的廣播接收器 if (receivers != null) { // ... // NT 表示靜態廣播接收器的數量 int NT = receivers != null ? receivers.size() : 0; int it = 0; ResolveInfo curt = null; BroadcastFilter curr = null; // 注意 NR 的值,前面發送非有序廣播給動態接收器時,NR 重置為 0 // 如果此時 NR 還不為 0, 那么表示發送的是有序廣播 // 那么根據廣播的優先級,按照從高到低的順序,把動態廣播接收器和靜態廣播接收器,合并到 receivers 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); } // 5. “序列化”地發送廣播 // 注意,這里分兩種情況 // 如果發送的非有序廣播,那么 receivers 只保存了靜態注冊的廣播接收器 // 如果發送的是有序廣播,那么 receivers 保存了靜態和動態注冊的廣播接收器 if ((receivers != null && receivers.size() > 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); final BroadcastRecord oldRecord = replacePending ? queue.replaceOrderedBroadcastLocked(r) : null; if (oldRecord != null) { // 處理替換廣播的情況 .... } else { queue.enqueueOrderedBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } } else { // 沒有找到接收廣播的接收器,簡單記錄下這個發送廣播的操作 ... } return ActivityManager.BROADCAST_SUCCESS; }
這段代碼設計的并不是很好,很多細節都雜糅到一個方法中。對于一些細節,我進行了詳細的注釋,有興趣的讀者可以自行研究,而本文只關心發送廣播的主要流程。
我不打算按照代碼的邏輯來講解流程,我自己總結了一套流程。
對于非有序廣播(包括 sticky 廣播),發送流程如下
把廣播“并行”地發送給動態廣播接收器。
把廣播“串行”地發送給靜態廣播接收器。
為何要把非有序廣播(包括 sticky 廣播)優先發送給動態接收器?最簡單的理由就是,不需要先拉起進程!因為"快”,所以先發送。
對于有序廣播,發送的流程如下
按照廣播的優先級,從高到低,把動態和靜態廣播接收器,合并到一起。
“串行”發送廣播給所有的接收器。
有序廣播,為何不先發送給動態接收器呢?因為它強調一個“有序”,所以要根據優先級來發送。
對于 sticky 廣播,由于它的特性,是需要對它的廣播 Intent 進行緩存的。根據前面注冊廣播接收器的分析,當注冊的廣播接收器匹配到緩存的 sticky 廣播 Intent,那么會立即返回數據給接收方,無論是通過函數的返回值,還是直接調用 BroadcastReceiver#onReceive()。
以上就是“ActivityManagerService廣播怎么注冊與發送”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。