framework/base/services/core/java/com/android/server/ - ActivityManagerService.java - BroadcastQueue.java - BroadcastFilter.java - BroadcastRecord.java - ReceiverList.java - ProcessRecord.java framework/base/core/java/android/content/ - BroadcastReceiver.java - IntentFilter.java framework/base/core/java/android/app/ - ActivityManagerNative.java (內含AMP) - ActivityManager.java - ApplicationThreadNative.java (內含ATP) - ActivityThread.java (內含ApplicationThread) - ContextImpl.java - LoadedApk
一、概述
廣播(Broadcast)機制用於進程/線程間通信,廣播分為廣播發送和廣播接收兩個過程,其中廣播接收者BroadcastReceiver便是Android四大組件之一。
BroadcastReceiver分為兩類:
- 靜態廣播接收者:通過AndroidManifest.xml的標簽來申明的BroadcastReceiver。
- 動態廣播接收者:通過AMS.registerReceiver()方式注冊的BroadcastReceiver,動態注冊更為靈活,可在不需要時通過unregisterReceiver()取消注冊。
從廣播發送方式可分為三類:
- 普通廣播:通過Context.sendBroadcast()發送,可並行處理
- 有序廣播:通過Context.sendOrderedBroadcast()發送,串行處理
- Sticky廣播:通過Context.sendStickyBroadcast()發送
1.1 BroadcastRecord
廣播在系統中以BroadcastRecord對象來記錄, 該對象有幾個時間相關的成員變量.
final class BroadcastRecord extends Binder { final ProcessRecord callerApp; //廣播發送者所在進程 final String callerPackage; //廣播發送者所在包名 final List receivers; // 包括動態注冊的BroadcastFilter和靜態注冊的ResolveInfo final String callerPackage; //廣播發送者 final int callingPid; // 廣播發送者pid final List receivers; // 廣播接收者 int nextReceiver; // 下一個被執行的接收者 IBinder receiver; // 當前正在處理的接收者 int anrCount; //廣播ANR次數 long enqueueClockTime; //入隊列時間 long dispatchTime; //分發時間 long dispatchClockTime; //分發時間 long receiverTime; //接收時間(首次等於dispatchClockTime) long finishTime; //廣播完成時間 }
- enqueueClockTime 伴隨着 scheduleBroadcastsLocked
- dispatchClockTime伴隨着 deliverToRegisteredReceiverLocked
- finishTime 位於 addBroadcastToHistoryLocked方法內
二、注冊廣播
廣播注冊,對於應用開發來說,往往是在Activity/Service中調用registerReceiver()
方法,而Activity或Service都間接繼承於Context抽象類,真正干活是交給ContextImpl類。另外調用getOuterContext()可獲取最外層的調用者Activity或Service。
2.1 registerReceiver
[ContextImpl.java]
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { return registerReceiver(receiver, filter, null, null); } public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) { return registerReceiverInternal(receiver, getUserId(), filter, broadcastPermission, scheduler, getOuterContext()); }
其中broadcastPermission擁有廣播的權限控制,scheduler用於指定接收到廣播時onRecive執行線程,當scheduler=null則默認代表在主線程中執行,這也是最常見的用法
2.2 registerReceiverInternal
[ContextImpl.java]
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId, IntentFilter filter, String broadcastPermission, Handler scheduler, Context context) { IIntentReceiver rd = null; if (receiver != null) { if (mPackageInfo != null && context != null) { if (scheduler == null) { //將主線程Handler賦予scheuler scheduler = mMainThread.getHandler(); } //獲取IIntentReceiver對象【2.3】 rd = mPackageInfo.getReceiverDispatcher( receiver, context, scheduler, mMainThread.getInstrumentation(), true); } else { if (scheduler == null) { scheduler = mMainThread.getHandler(); } rd = new LoadedApk.ReceiverDispatcher( receiver, context, scheduler, null, true).getIIntentReceiver(); } } try { //調用AMP.registerReceiver 【2.4】 return ActivityManagerNative.getDefault().registerReceiver( mMainThread.getApplicationThread(), mBasePackageName, rd, filter, broadcastPermission, userId); } catch (RemoteException e) { return null; } }
ActivityManagerNative.getDefault()返回的是ActivityManagerProxy對象,簡稱AMP.
該方法中參數有mMainThread.getApplicationThread()返回的是ApplicationThread,這是Binder的Bn端,用於system_server進程與該進程的通信。
2.3 LoadedApk.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; //此處registered=true,則進入該分支 if (registered) { map = mReceivers.get(context); if (map != null) { rd = map.get(r); } } if (rd == null) { //當廣播分發者為空,則創建ReceiverDispatcher【2.3.1】 rd = new ReceiverDispatcher(r, context, handler, instrumentation, registered); if (registered) { if (map == null) { map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); mReceivers.put(context, map); } map.put(r, rd); } } else { //驗證廣播分發者的context、handler是否一致 rd.validate(context, handler); } rd.mForgotten = false; //獲取IIntentReceiver對象 return rd.getIIntentReceiver(); } }
不妨令 以BroadcastReceiver(廣播接收者)為key,LoadedApk.ReceiverDispatcher(分發者)為value的ArrayMap 記為A
。此處mReceivers
是一個以Context
為key,以A
為value的ArrayMap。對於ReceiverDispatcher(廣播分發者),當不存在時則創建一個。
2.3.1 創建ReceiverDispatcher
ReceiverDispatcher(BroadcastReceiver receiver, Context context,
Handler activityThread, Instrumentation instrumentation,
boolean registered) { //創建InnerReceiver【2.3.2】 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
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; } ... }
ReceiverDispatcher(廣播分發者)有一個內部類InnerReceiver
,該類繼承於IIntentReceiver.Stub
。顯然,這是一個Binder服務端,廣播分發者通過rd.getIIntentReceiver()可獲取該Binder服務端對象InnerReceiver
,用於Binder IPC通信。
2.4 AMP.registerReceiver
[-> ActivityManagerNative.java]
public Intent registerReceiver(IApplicationThread caller, String packageName, IIntentReceiver receiver, IntentFilter filter, String perm, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(caller != null ? caller.asBinder() : null); data.writeString(packageName); data.writeStrongBinder(receiver != null ? receiver.asBinder() : null); filter.writeToParcel(data, 0); data.writeString(perm); data.writeInt(userId); //Command為REGISTER_RECEIVER_TRANSACTION mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0); reply.readException(); Intent intent = null; int haveIntent = reply.readInt(); if (haveIntent != 0) { intent = Intent.CREATOR.createFromParcel(reply); } reply.recycle(); data.recycle(); return intent; }
這里有兩個Binder服務端對象caller
和receiver
,都代表執行注冊廣播動作所在的進程. AMP通過Binder驅動將這些信息發送給system_server進程中的AMS對象,接下來進入AMS.registerReceiver。
2.5 AMS.registerReceiver
[-> ActivityManagerService.java]
public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId) { ArrayList<Intent> stickyIntents = null; ProcessRecord callerApp = null; ... synchronized(this) { if (caller != null) { //從mLruProcesses查詢調用者的進程信息【見2.5.1】 callerApp = getRecordForAppLocked(caller); ... callingUid = callerApp.info.uid; callingPid = callerApp.pid; } else { callerPackage = null; callingUid = Binder.getCallingUid(); callingPid = Binder.getCallingPid(); } userId = handleIncomingUser(callingPid, callingUid, userId, true, ALLOW_FULL_ONLY, "registerReceiver", callerPackage); //獲取IntentFilter中的actions. 這就是平時所加需要監聽的廣播action Iterator<String> actions = filter.actionsIterator(); if (actions == null) { ArrayList<String> noAction = new ArrayList<String>(1); noAction.add(null); actions = noAction.iterator(); } int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) }; while (actions.hasNext()) { String action = actions.next(); for (int id : userIds) { //從mStickyBroadcasts中查看用戶的sticky Intent 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>(); } //將sticky Intent加入到隊列 stickyIntents.addAll(intents); } } } } } ArrayList<Intent> allSticky = null; if (stickyIntents != null) { final ContentResolver resolver = mContext.getContentResolver(); for (int i = 0, N = stickyIntents.size(); i < N; i++) { Intent intent = stickyIntents.get(i); //查詢匹配的sticky廣播 【見2.5.2】 if (filter.match(resolver, intent, true, TAG) >= 0) { if (allSticky == null) { allSticky = new ArrayList<Intent>(); } //匹配成功,則將給intent添加到allSticky隊列 allSticky.add(intent); } } } //當IIntentReceiver為空,則直接返回第一個sticky Intent, Intent sticky = allSticky != null ? allSticky.get(0) : null; if (receiver == null) { return sticky; } synchronized (this) { if (callerApp != null && (callerApp.thread == null || callerApp.thread.asBinder() != caller.asBinder())) { return null; //調用者已經死亡 } ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder()); if (rl == null) { //對於沒有注冊的廣播,則創建接收者隊列 rl = new ReceiverList(this, callerApp, callingPid, callingUid, userId, receiver); if (rl.app != null) { rl.app.receivers.add(rl); } else { receiver.asBinder().linkToDeath(rl, 0); //注冊死亡通知 ... rl.linkedToDeath = true; } //新創建的接收者隊列,添加到已注冊廣播隊列。 mRegisteredReceivers.put(receiver.asBinder(), rl); } ... //創建BroadcastFilter對象,並添加到接收者隊列 BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userId); rl.add(bf); //新創建的廣播過濾者,添加到ReceiverResolver隊列 mReceiverResolver.addFilter(bf); //所有匹配該filter的sticky廣播執行入隊操作 //如果沒有使用sendStickyBroadcast,則allSticky=null。 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.5.3】 BroadcastQueue queue = broadcastQueueForIntent(intent); //創建BroadcastRecord BroadcastRecord r = new BroadcastRecord(queue, intent, null, null, -1, -1, null, null, AppOpsManager.OP_NONE, null, receivers, null, 0, null, null, false, true, true, -1); //該廣播加入到並行廣播隊列 queue.enqueueParallelBroadcastLocked(r); //調度廣播,發送BROADCAST_INTENT_MSG消息,觸發處理下一個廣播。 queue.scheduleBroadcastsLocked(); } } return sticky; } }
其中mRegisteredReceivers
記錄着所有已注冊的廣播,以receiver IBinder為key, ReceiverList為value為HashMap。
在BroadcastQueue中有兩個廣播隊列mParallelBroadcasts,mOrderedBroadcasts,數據類型都為ArrayList:
mParallelBroadcasts
:並行廣播隊列,可以立刻執行,而無需等待另一個廣播運行完成,該隊列只允許動態已注冊的廣播,從而避免發生同時拉起大量進程來執行廣播,前台的和后台的廣播分別位於獨立的隊列。mOrderedBroadcasts
:有序廣播隊列,同一時間只允許執行一個廣播,該隊列頂部的廣播便是活動廣播,其他廣播必須等待該廣播結束才能運行,也是獨立區別前台的和后台的廣播。
2.5.1 AMS.getRecordForAppLocked
final ProcessRecord getRecordForAppLocked( IApplicationThread thread) { if (thread == null) { return null; } //從mLruProcesses隊列中查看 int appIndex = getLRURecordIndexForAppLocked(thread); return appIndex >= 0 ? mLruProcesses.get(appIndex) : null; }
mLruProcesses數據類型為ArrayList<ProcessRecord>
,而ProcessRecord對象有一個IApplicationThread字段,根據該字段查找出滿足條件的ProcessRecord對象。
2.5.2 IntentFilter.match
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)) { return NO_MATCH_ACTION; } //不存在匹配的type或data int dataMatch = matchData(type, scheme, data); if (dataMatch < 0) { return dataMatch; } //不存在匹配的category String categoryMismatch = matchCategories(categories); if (categoryMismatch != null) { return NO_MATCH_CATEGORY; } return dataMatch; }
該方法用於匹配發起的Intent數據是否匹配成功,匹配項共有4項action, type, data, category,任何一項匹配不成功都會失敗。
2.5.3 AMS.broadcastQueueForIntent
BroadcastQueue broadcastQueueForIntent(Intent intent) { final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0; return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue; }
broadcastQueueForIntent(Intent intent)通過判斷intent.getFlags()是否包含FLAG_RECEIVER_FOREGROUND 來決定是前台或后台廣播,進而返回相應的廣播隊列mFgBroadcastQueue或者mBgBroadcastQueue。
- 當Intent的flags包含FLAG_RECEIVER_FOREGROUND,則返回mFgBroadcastQueue;
- 當Intent的flags不包含FLAG_RECEIVER_FOREGROUND,則返回mBgBroadcastQueue;
2.6 廣播注冊小結
注冊廣播:
- 傳遞的參數為廣播接收者BroadcastReceiver和Intent過濾條件IntentFilter;
- 創建對象LoadedApk.ReceiverDispatcher.InnerReceiver,該對象繼承於IIntentReceiver.Stub;
- 通過AMS把當前進程的ApplicationThread和InnerReceiver對象的代理類,注冊登記到system_server進程;
- 當廣播receiver沒有注冊過,則創建廣播接收者隊列ReceiverList,該對象繼承於ArrayList, 並添加到AMS.mRegisteredReceivers(已注冊廣播隊列);
- 創建BroadcastFilter,並添加到AMS.mReceiverResolver;
- 將BroadcastFilter添加到該廣播接收者的ReceiverList
另外,當注冊的是Sticky廣播:
- 創建BroadcastRecord,並添加到BroadcastQueue的mParallelBroadcasts(並行廣播隊列),注冊后調用AMS來盡快處理該廣播。
- 根據注冊廣播的Intent是否包含FLAG_RECEIVER_FOREGROUND,則mFgBroadcastQueue
廣播注冊完, 另一個操作便是在廣播發送過程.
三、 發送廣播
發送廣播是在Activity或Service中調用sendBroadcast()
方法,而Activity或Service都間接繼承於Context抽象類,真正干活是交給ContextImpl類。
3.1 sendBroadcast
[ContextImpl.java]
public void sendBroadcast(Intent intent) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(); // 調用AMP.broadcastIntent 【見3.2】 ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false, getUserId()); } catch (RemoteException e) { ... } }
3.2 AMP.broadcastIntent
[-> ActivityManagerNative.java]
public int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String[] requiredPermissions, int appOp, Bundle options, boolean serialized, boolean sticky, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(caller != null ? caller.asBinder() : null); intent.writeToParcel(data, 0); data.writeString(resolvedType); data.writeStrongBinder(resultTo != null ? resultTo.asBinder() : null); data.writeInt(resultCode); data.writeString(resultData); data.writeBundle(map); data.writeStringArray(requiredPermissions); data.writeInt(appOp); data.writeBundle(options); data.writeInt(serialized ? 1 : 0); data.writeInt(sticky ? 1 : 0); data.writeInt(userId); //Command為BROADCAST_INTENT_TRANSACTION mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0); reply.readException(); int res = reply.readInt(); reply.recycle(); data.recycle(); return res; }
3.3 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 options, 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.4】 int res = broadcastIntentLocked(callerApp, callerApp != null ? callerApp.info.packageName : null, intent, resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions, appOp, null, serialized, sticky, callingPid, callingUid, userId); Binder.restoreCallingIdentity(origId); return res; } }
broadcastIntent()方法有兩個布爾參數serialized和sticky來共同決定是普通廣播,有序廣播,還是Sticky廣播,參數如下:
類型 | serialized | sticky |
---|---|---|
sendBroadcast | false | false |
sendOrderedBroadcast | true | false |
sendStickyBroadcast | false | true |
3.4 AMS.broadcastIntentLocked
private final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle options, boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) { //step1: 設置flag //step2: 廣播權限驗證 //step3: 處理系統相關廣播 //step4: 增加sticky廣播 //step5: 查詢receivers和registeredReceivers //step6: 處理並行廣播 //step7: 合並registeredReceivers到receivers //step8: 處理串行廣播 return ActivityManager.BROADCAST_SUCCESS; }
broadcastIntentLocked方法比較長,這里划分為8個部分來分別說明。
3.4.1 設置廣播flag
intent = new Intent(intent); //增加該flag,則廣播不會發送給已停止的package intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); //當沒有啟動完成時,不允許啟動新進程 if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); } userId = handleIncomingUser(callingPid, callingUid, userId, true, ALLOW_NON_FULL, "broadcast", callerPackage); //檢查發送廣播時用戶狀態 if (userId != UserHandle.USER_ALL && !isUserRunningLocked(userId, false)) { if ((callingUid != Process.SYSTEM_UID || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) { return ActivityManager.BROADCAST_FAILED_USER_STOPPED; } }
這個過程最重要的工作是:
- 添加flag=
FLAG_EXCLUDE_STOPPED_PACKAGES
,保證已停止app不會收到該廣播; - 當系統還沒有啟動完成,則不允許啟動新進程,,即只有動態注冊receiver才能接受廣播
- 當非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 //升級模式下,允許系統准備就緒前可以發送廣播
3.4.2 廣播權限驗證
int callingAppId = UserHandle.getAppId(callingUid); if (callingAppId == Process.SYSTEM_UID || callingAppId == Process.PHONE_UID || callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID || callingAppId == Process.NFC_UID || callingUid == 0) { //直接通過 } else if (callerApp == null || !callerApp.persistent) { try { if (AppGlobals.getPackageManager().isProtectedBroadcast( intent.getAction())) { //不允許發送給受保護的廣播 throw new SecurityException(msg); } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(intent.getAction())) { ... } } catch (RemoteException e) { return ActivityManager.BROADCAST_SUCCESS; } }
主要功能:
- 對於callingAppId為SYSTEM_UID,PHONE_UID,SHELL_UID,BLUETOOTH_UID,NFC_UID之一或者callingUid == 0時都暢通無阻;
- 否則當調用者進程為空 或者非persistent進程的情況下:
- 當發送的是受保護廣播
mProtectedBroadcasts
(只允許系統使用),則拋出異常; - 當action為ACTION_APPWIDGET_CONFIGURE時,雖然不希望該應用發送這種廣播,處於兼容性考慮,限制該廣播只允許發送給自己,否則拋出異常。
- 當發送的是受保護廣播
3.4.3 處理系統相關廣播
final String action = intent.getAction(); if (action != null) { switch (action) { case Intent.ACTION_UID_REMOVED: //uid移除 case Intent.ACTION_PACKAGE_REMOVED: //package移除 case Intent.ACTION_PACKAGE_ADDED: //增加package case Intent.ACTION_PACKAGE_CHANGED: //package改變 case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE: //外部設備不可用 case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE: //外部設備可用 case Intent.ACTION_TIMEZONE_CHANGED: //時區改變,通知所有運行中的進程 case Intent.ACTION_TIME_CHANGED: //時間改變,通知所有運行中的進程 case Intent.ACTION_CLEAR_DNS_CACHE: //DNS緩存清空 case Proxy.PROXY_CHANGE_ACTION: //網絡代理改變 } }
這個過主要處於系統相關的10類廣播,這里不就展開講解了.
3.4.4 增加sticky廣播
if (sticky) { if (checkPermission(android.Manifest.permission.BROADCAST_STICKY, callingPid, callingUid) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException(""); } if (requiredPermissions != null && requiredPermissions.length > 0) { return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION; } if (intent.getComponent() != null) { //當sticky廣播發送給指定組件,則throw Exception } if (userId != UserHandle.USER_ALL) { //當非USER_ALL廣播跟USER_ALL廣播出現沖突,則throw Exception } 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))) { //替換已存在的sticky intent list.set(i, new Intent(intent)); break; } } //新的intent追加到list if (i >= stickiesCount) { list.add(new Intent(intent)); } }
這個過程主要是將sticky廣播增加到list,並放入mStickyBroadcasts里面。
3.4.5 查詢receivers和registeredReceivers
List receivers = null; List<BroadcastFilter> registeredReceivers = null; //當允許靜態接收者處理該廣播,則通過PKMS根據Intent查詢相應的靜態receivers if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { receivers = collectReceiverComponents(intent, resolvedType, callingUid, users); } if (intent.getComponent() == null) { if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) { ... } else { // 查詢相應的動態注冊的廣播 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false, userId); } }
- receivers:記錄着匹配當前intent的所有靜態注冊廣播接收者;
- registeredReceivers:記錄着匹配當前的所有動態注冊的廣播接收者。
其他說明:
- 根據userId來決定廣播是發送給全部的接收者,還是指定的userId;
- mReceiverResolver是AMS的成員變量,記錄着已注冊的廣播接收者的resolver.
AMS.collectReceiverComponents:
private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType, int callingUid, int[] users) { List<ResolveInfo> receivers = null; for (int user : users) { //調用PKMS.queryIntentReceivers,可獲取AndroidManifest.xml聲明的接收者信息 List<ResolveInfo> newReceivers = AppGlobals.getPackageManager() .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user); if (receivers == null) { receivers = newReceivers; } else if (newReceivers != null) { ... //將所用戶的receiver整合到receivers } } return receivers; }
3.4.6 處理並行廣播
//用於標識是否需要用新intent替換舊的intent。 final boolean replacePending = (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0; //處理並行廣播 int NR = registeredReceivers != null ? registeredReceivers.size() : 0; if (!ordered && NR > 0) { final BroadcastQueue queue = broadcastQueueForIntent(intent); //創建BroadcastRecord對象 BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callingPid, callingUid, resolvedType, requiredPermissions, appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId); final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r); if (!replaced) { //將BroadcastRecord加入到並行廣播隊列[見下文] queue.enqueueParallelBroadcastLocked(r); //處理廣播【見小節4.1】 queue.scheduleBroadcastsLocked(); } //動態注冊的廣播接收者處理完成,則會置空該變量; registeredReceivers = null; NR = 0; }
廣播隊列中有一個成員變量mParallelBroadcasts
,類型為ArrayList,記錄着所有的並行廣播。
// 並行廣播,加入mParallelBroadcasts隊列 public void enqueueParallelBroadcastLocked(BroadcastRecord r) { mParallelBroadcasts.add(r); r.enqueueClockTime = System.currentTimeMillis(); }
3.4.7 合並registeredReceivers到receivers
int ir = 0; if (receivers != null) { //防止應用監聽該廣播,在安裝時直接運行。 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)) { ... } //[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) { receivers.add(it, curr); ir++; curr = null; it++; NT++; } else { it++; curt = null; } } } while (ir < NR) { if (receivers == null) { receivers = new ArrayList(); } receivers.add(registeredReceivers.get(ir)); ir++; }
動態注冊的registeredReceivers,全部合並都receivers,再統一按串行方式處理。
3.4.8 處理串行廣播
if ((receivers != null && receivers.size() > 0) || resultTo != null) { BroadcastQueue queue = broadcastQueueForIntent(intent); //創建BroadcastRecord BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callingPid, callingUid, resolvedType, requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId); boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r); if (!replaced) { //將BroadcastRecord加入到有序廣播隊列 queue.enqueueOrderedBroadcastLocked(r); //處理廣播【見小節4.1】 queue.scheduleBroadcastsLocked(); } }
廣播隊列中有一個成員變量mOrderedBroadcasts
,類型為ArrayList,記錄着所有的有序廣播。
// 串行廣播 加入mOrderedBroadcasts隊列 public void enqueueOrderedBroadcastLocked(BroadcastRecord r) { mOrderedBroadcasts.add(r); r.enqueueClockTime = System.currentTimeMillis(); }
3.5 小結
發送廣播過程:
- 默認不發送給已停止(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES)的應用包;
- 處理各種PACKAGE,TIMEZONE等相關的系統廣播;
- 當為粘性廣播,則將sticky廣播增加到list,並放入mStickyBroadcasts里面;
- 當廣播的Intent沒有設置FLAG_RECEIVER_REGISTERED_ONLY,則允許靜態廣播接收者來處理該廣播; 創建BroadcastRecord對象,並將該對象加入到相應的廣播隊列, 然后調用BroadcastQueue的
scheduleBroadcastsLocked
()方法來完成的不同廣播處理:
處理方式:
- Sticky廣播: 廣播注冊過程處理AMS.registerReceiver,開始處理粘性廣播,見小節[2.5];
- 創建BroadcastRecord對象;
- 並添加到mParallelBroadcasts隊列;
- 然后執行queue.scheduleBroadcastsLocked;
- 並行廣播: 廣播發送過程處理,見小節[3.4.6]
- 只有動態注冊的mRegisteredReceivers才會並行處理;
- 會創建BroadcastRecord對象;
- 並添加到mParallelBroadcasts隊列;
- 然后執行queue.scheduleBroadcastsLocked;
- 串行廣播: 廣播發送廣播處理,見小節[3.4.8]
- 所有靜態注冊的receivers以及動態注冊mRegisteredReceivers合並到一張表處理;
- 創建BroadcastRecord對象;
- 並添加到mOrderedBroadcasts隊列;
- 然后執行queue.scheduleBroadcastsLocked;
可見不管哪種廣播方式,接下來都會執行scheduleBroadcastsLocked方法來處理廣播;
四、 處理廣播
在發送廣播過程中會執行scheduleBroadcastsLocked
方法來處理相關的廣播
4.1 scheduleBroadcastsLocked
[-> BroadcastQueue.java]
public void scheduleBroadcastsLocked() { // 正在處理BROADCAST_INTENT_MSG消息 if (mBroadcastsScheduled) { return; } //發送BROADCAST_INTENT_MSG消息 mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this)); mBroadcastsScheduled = true; }
在BroadcastQueue對象創建時,mHandler=new BroadcastHandler(handler.getLooper());那么此處交由mHandler的handleMessage來處理:
4.1.1 BroadcastHandler
public ActivityManagerService(Context systemContext) { //名為"ActivityManager"的線程 mHandlerThread = new ServiceThread(TAG, android.os.Process.THREAD_PRIORITY_FOREGROUND, false); 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); ... } BroadcastQueue(ActivityManagerService service, Handler handler, String name, long timeoutPeriod, boolean allowDelayBehindServices) { mService = service; //創建BroadcastHandler mHandler = new BroadcastHandler(handler.getLooper()); mQueueName = name; mTimeoutPeriod = timeoutPeriod; mDelayBehindServices = allowDelayBehindServices; }
由此可見BroadcastHandler采用的是”ActivityManager”線程的Looper
private final class BroadcastHandler extends Handler { public void handleMessage(Message msg) { switch (msg.what) { case BROADCAST_INTENT_MSG: { processNextBroadcast(true); //【見小節4.2】 } break; ... } }
4.2 processNextBroadcast
[-> BroadcastQueue.java]
final void processNextBroadcast(boolean fromMsg) { synchronized(mService) { //part1: 處理並行廣播 while (mParallelBroadcasts.size() > 0) { r = mParallelBroadcasts.remove(0); r.dispatchTime = SystemClock.uptimeMillis(); r.dispatchClockTime = System.currentTimeMillis(); final int N = r.receivers.size(); for (int i=0; i<N; i++) { Object target = r.receivers.get(i); //分發廣播給已注冊的receiver 【見小節4.3】 deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false); } addBroadcastToHistoryLocked(r);//將廣播添加歷史統計 } //part2: 處理當前有序廣播 do { if (mOrderedBroadcasts.size() == 0) { mService.scheduleAppGcsLocked(); //沒有更多的廣播等待處理 if (looped) { mService.updateOomAdjLocked(); } return; } r = mOrderedBroadcasts.get(0); //獲取串行廣播的第一個廣播 boolean forceReceive = false; int numReceivers = (r.receivers != null) ? r.receivers.size() : 0; if (mService.mProcessesReady && r.dispatchTime > 0) { long now = SystemClock.uptimeMillis(); if ((numReceivers > 0) && (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) { broadcastTimeoutLocked(false); //當廣播處理時間超時,則強制結束這條廣播 } } ... if (r.receivers == null || r.nextReceiver >= numReceivers || r.resultAbort || forceReceive) { if (r.resultTo != null) { //處理廣播消息消息,調用到onReceive() performReceiveLocked(r.callerApp, r.resultTo, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, false, false, r.userId); } cancelBroadcastTimeoutLocked(); //取消BROADCAST_TIMEOUT_MSG消息 addBroadcastToHistoryLocked(r); mOrderedBroadcasts.remove(0); continue; } } while (r == null); //part3: 獲取下一個receiver r.receiverTime = SystemClock.uptimeMillis(); if (recIdx == 0) { r.dispatchTime = r.receiverTime; r.dispatchClockTime = System.currentTimeMillis(); } if (!mPendingBroadcastTimeoutMessage) { long timeoutTime = r.receiverTime + mTimeoutPeriod; setBroadcastTimeoutLocked(timeoutTime); //設置廣播超時延時消息 } //part4: 處理下條有序廣播 ProcessRecord app = mService.getProcessRecordLocked(targetProcess, info.activityInfo.applicationInfo.uid, false); if (app != null && app.thread != null) { app.addPackage(info.activityInfo.packageName, info.activityInfo.applicationInfo.versionCode, mService.mProcessStats); processCurBroadcastLocked(r, app); //[處理串行廣播] return; ... } //該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) { ... return; } } }
此處mService為AMS,整個流程還是比較長的,全程持有AMS鎖,所以廣播效率低的情況下,直接會嚴重影響這個手機的性能與流暢度,這里應該考慮細化同步鎖的粒度。
- 設置廣播超時延時消息: setBroadcastTimeoutLocked:
- 當廣播接收者等待時間過長,則調用broadcastTimeoutLocked(false);
- 當執行完廣播,則調用cancelBroadcastTimeoutLocked;
4.2.1 處理並行廣播
BroadcastRecord r;
mService.updateCpuStats(); //更新CPU統計信息 if (fromMsg) mBroadcastsScheduled = false; while (mParallelBroadcasts.size() > 0) { r = mParallelBroadcasts.remove(0); r.dispatchTime = SystemClock.uptimeMillis(); r.dispatchClockTime = System.currentTimeMillis(); final int N = r.receivers.size(); for (int i=0; i<N; i++) { Object target = r.receivers.get(i); //分發廣播給已注冊的receiver 【見小節4.3】 deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false); } addBroadcastToHistoryLocked(r);//將廣播添加歷史統計 }
通過while循環, 一次性分發完所有的並發廣播后,則分發完成后則添加到歷史廣播隊列. fromMsg是指processNextBroadcast()是否由BroadcastHandler所調用的.
private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
if (r.callingUid < 0) { return; } r.finishTime = SystemClock.uptimeMillis(); //記錄分發完成時間 mBroadcastHistory[mHistoryNext] = r; mHistoryNext = ringAdvance(mHistoryNext, 1, MAX_BROADCAST_HISTORY); mBroadcastSummaryHistory[mSummaryHistoryNext] = r.intent; mSummaryHistoryEnqueueTime[mSummaryHistoryNext] = r.enqueueClockTime; mSummaryHistoryDispatchTime[mSummaryHistoryNext] = r.dispatchClockTime; mSummaryHistoryFinishTime[mSummaryHistoryNext] = System.currentTimeMillis(); mSummaryHistoryNext = ringAdvance(mSummaryHistoryNext, 1, MAX_BROADCAST_SUMMARY_HISTORY); }
4.2.2 處理串行廣播
if (mPendingBroadcast != null) { boolean isDead; synchronized (mService.mPidsSelfLocked) { //從mPidsSelfLocked獲取正在處理該廣播進程,判斷該進程是否死亡 ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid); isDead = proc == null || proc.crashing; } if (!isDead) { return; //正在處理廣播的進程保持活躍狀態,則繼續等待其執行完成 } else { mPendingBroadcast.state = BroadcastRecord.IDLE; mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex; mPendingBroadcast = null; } } boolean looped = false; do { if (mOrderedBroadcasts.size() == 0) { //所有串行廣播處理完成,則調度執行gc mService.scheduleAppGcsLocked(); if (looped) { mService.updateOomAdjLocked(); } return; } r = mOrderedBroadcasts.get(0); boolean forceReceive = false; //獲取所有該廣播所有的接收者 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0; if (mService.mProcessesReady && r.dispatchTime > 0) { long now = SystemClock.uptimeMillis(); if ((numReceivers > 0) && (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) { //當廣播處理時間超時,則強制結束這條廣播 broadcastTimeoutLocked(false); forceReceive = true; r.state = BroadcastRecord.IDLE; } } if (r.state != BroadcastRecord.IDLE) { return; } if (r.receivers == null || r.nextReceiver >= numReceivers || r.resultAbort || forceReceive) { if (r.resultTo != null) { //處理廣播消息消息,調用到onReceive() performReceiveLocked(r.callerApp, r.resultTo, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, false, false, r.userId); r.resultTo = null; } //取消BROADCAST_TIMEOUT_MSG消息 cancelBroadcastTimeoutLocked(); addBroadcastToHistoryLocked(r); mOrderedBroadcasts.remove(0); r = null; looped = true; continue; } } while (r == null);
mTimeoutPeriod,對於前台廣播則為10s,對於后台廣播則為60s。廣播超時為2*mTimeoutPeriod*numReceivers
,接收者個數numReceivers越多則廣播超時總時長越大。
4.2.3 獲取下條有序廣播
//獲取下一個receiver的index int recIdx = r.nextReceiver++; r.receiverTime = SystemClock.uptimeMillis(); if (recIdx == 0) { r.dispatchTime = r.receiverTime; r.dispatchClockTime = System.currentTimeMillis(); } if (!mPendingBroadcastTimeoutMessage) { long timeoutTime = r.receiverTime + mTimeoutPeriod; //設置廣播超時時間,發送BROADCAST_TIMEOUT_MSG setBroadcastTimeoutLocked(timeoutTime); } final BroadcastOptions brOptions = r.options; //獲取下一個廣播接收者 final Object nextReceiver = r.receivers.get(recIdx); if (nextReceiver instanceof BroadcastFilter) { //對於動態注冊的廣播接收者,deliverToRegisteredReceiverLocked處理廣播 BroadcastFilter filter = (BroadcastFilter)nextReceiver; deliverToRegisteredReceiverLocked(r, filter, r.ordered); if (r.receiver == null || !r.ordered) { r.state = BroadcastRecord.IDLE; scheduleBroadcastsLocked(); } else { ... } return; } //對於靜態注冊的廣播接收者 ResolveInfo info = (ResolveInfo)nextReceiver; ComponentName component = new ComponentName( info.activityInfo.applicationInfo.packageName, info.activityInfo.name); ... //執行各種權限檢測,此處省略,當權限不滿足時skip=true if (skip) { r.receiver = null; r.curFilter = null; r.state = BroadcastRecord.IDLE; scheduleBroadcastsLocked(); return; } r.state = BroadcastRecord.APP_RECEIVE; String targetProcess = info.activityInfo.processName; r.curComponent = component; final int receiverUid = info.activityInfo.applicationInfo.uid; if (r.callingUid != Process.SYSTEM_UID && isSingleton && mService.isValidSingletonCall(r.callingUid, receiverUid)) { info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0); } r.curReceiver = info.activityInfo; ... //Broadcast正在執行中,stopped狀態設置成false AppGlobals.getPackageManager().setPackageStoppedState( r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid));
4.2.4 處理下條有序廣播
//該receiver所對應的進程已經運行,則直接處理 ProcessRecord app = mService.getProcessRecordLocked(targetProcess, info.activityInfo.applicationInfo.uid, false); if (app != null && app.thread != null) { try { app.addPackage(info.activityInfo.packageName, info.activityInfo.applicationInfo.versionCode, mService.mProcessStats); processCurBroadcastLocked(r, app); return; } catch (RemoteException e) { } catch (RuntimeException e) { finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false); scheduleBroadcastsLocked(); r.state = BroadcastRecord.IDLE; //啟動receiver失敗則重置狀態 return; } } //該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) { //創建失敗,則結束該receiver finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false); scheduleBroadcastsLocked(); r.state = BroadcastRecord.IDLE; return; } mPendingBroadcast = r; mPendingBroadcastRecvIndex = recIdx;
- 如果是動態廣播接收者,則調用deliverToRegisteredReceiverLocked處理;
- 如果是靜態廣播接收者,且對應進程已經創建,則調用processCurBroadcastLocked處理;
- 如果是靜態廣播接收者,且對應進程尚未創建,則調用startProcessLocked創建進程。
接下來,介紹deliverToRegisteredReceiverLocked的處理流程:
4.3 deliverToRegisteredReceiverLocked
[-> BroadcastQueue.java]
private void deliverToRegisteredReceiverLocked(BroadcastRecord r, BroadcastFilter filter, boolean ordered) { ... //檢查發送者是否有BroadcastFilter所需權限 //以及接收者是否有發送者所需的權限等等 //當權限不滿足要求,則skip=true。 if (!skip) { //並行廣播ordered = false,只有串行廣播才進入該分支 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) { r.curApp = filter.receiverList.app; filter.receiverList.app.curReceiver = r; mService.updateOomAdjLocked(r.curApp); } } // 處理廣播【見小節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; } ... } }
4.4 performReceiveLocked
[-> BroadcastQueue.java]
private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) throws RemoteException { //通過binder異步機制,向receiver發送intent if (app != null) { if (app.thread != null) { //調用ApplicationThreadProxy類對應的方法 【4.5】 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode, data, extras, ordered, sticky, sendingUser, app.repProcState); } else { //應用進程死亡,則Recevier並不存在 throw new RemoteException("app.thread must not be null"); } } else { //調用者進程為空,則執行該分支 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser); } }
4.5 ATP.scheduleRegisteredReceiver
[-> ApplicationThreadNative.java ::ApplicationThreadProxy]
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent, int resultCode, String dataStr, Bundle extras, boolean ordered, boolean sticky, int sendingUser, int processState) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeStrongBinder(receiver.asBinder()); intent.writeToParcel(data, 0); data.writeInt(resultCode); data.writeString(dataStr); data.writeBundle(extras); data.writeInt(ordered ? 1 : 0); data.writeInt(sticky ? 1 : 0); data.writeInt(sendingUser); data.writeInt(processState); //command=SCHEDULE_REGISTERED_RECEIVER_TRANSACTION mRemote.transact(SCHEDULE_REGISTERED_RECEIVER_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); }
ATP位於system_server進程,是Binder Bp端通過Binder驅動向Binder Bn端發送消息(oneway調用方式), ATP所對應的Bn端位於發送廣播調用端所在進程的ApplicationThread,即進入AT.scheduleRegisteredReceiver, 接下來說明該方法。
4.6 AT.scheduleRegisteredReceiver
[-> ActivityThread.java ::ApplicationThread]
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.7】 receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky, sendingUser); }
此處receiver是注冊廣播時創建的,見小節[2.3],可知該receiver
=LoadedApk.ReceiverDispatcher.InnerReceiver
。
4.7 InnerReceiver.performReceive
[-> LoadedApk.java]
public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { LoadedApk.ReceiverDispatcher rd = mDispatcher.get(); if (rd != null) { //【見小節4.8】 rd.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser); } else { ... } }
此處方法LoadedApk()屬於LoadedApk.ReceiverDispatcher.InnerReceiver, 也就是LoadedApk內部類的內部類InnerReceiver.
4.8 ReceiverDispatcher.performReceive
[-> LoadedApk.java]
public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { Args args = new Args(intent, resultCode, data, extras, ordered, sticky, sendingUser); //通過handler消息機制發送args. if (!mActivityThread.post(args)) { //消息成功post到主線程,則不會走此處。 if (mRegistered && ordered) { IActivityManager mgr = ActivityManagerNative.getDefault(); args.sendFinished(mgr); } } }
其中Args
繼承於BroadcastReceiver.PendingResult
,實現了接口Runnable
; 其中mActivityThread是當前進程的主線程, 是由[小節2.3.1]完成賦值過程.
這里mActivityThread.post(args) 消息機制,關於Handler消息機制,見Android消息機制1-Handler(Java層),把消息放入MessageQueue,再調用Args的run()方法。
4.9 ReceiverDispatcher.Args.run
[-> LoadedApk.java]
public final class LoadedApk { static final class ReceiverDispatcher { final class Args extends BroadcastReceiver.PendingResult implements Runnable { public void run() { final BroadcastReceiver receiver = mReceiver; final boolean ordered = mOrdered; final IActivityManager mgr = ActivityManagerNative.getDefault(); final Intent intent = mCurIntent; mCurIntent = null; if (receiver == null || mForgotten) { if (mRegistered && ordered) { sendFinished(mgr); } return; } try { //獲取mReceiver的類加載器 ClassLoader cl = mReceiver.getClass().getClassLoader(); intent.setExtrasClassLoader(cl); setExtrasClassLoader(cl); receiver.setPendingResult(this); //回調廣播onReceive方法 receiver.onReceive(mContext, intent); } catch (Exception e) { ... } if (receiver.getPendingResult() != null) { finish(); //【見小節4.10】 } } } }
接下來,便進入主線程,最終調用BroadcastReceiver
具體實現類的onReceive()
方法。
4.10 PendingResult.finish
[-> BroadcastReceiver.java ::PendingResult]
public final void finish() { if (mType == TYPE_COMPONENT) { //代表是靜態注冊的廣播 final IActivityManager mgr = ActivityManagerNative.getDefault(); if (QueuedWork.hasPendingWork()) { QueuedWork.singleThreadExecutor().execute( new Runnable() { void run() { sendFinished(mgr); //[見小節4.10.1] } }); } else { sendFinished(mgr); //[見小節4.10.1] } } else if (mOrderedHint && mType != TYPE_UNREGISTERED) { //動態注冊的串行廣播 final IActivityManager mgr = ActivityManagerNative.getDefault(); sendFinished(mgr); //[見小節4.10.1] } }
主要功能:
- 靜態注冊的廣播接收者:
- 當QueuedWork工作未完成, 即SharedPreferences寫入磁盤的操作沒有完成, 則等待完成再執行sendFinished方法;
- 當QueuedWork工作已完成, 則直接調用sendFinished方法;
- 動態注冊的廣播接收者:
- 當發送的是串行廣播, 則直接調用sendFinished方法.
另外常量參數說明:
- TYPE_COMPONENT: 靜態注冊
- TYPE_REGISTERED: 動態注冊
- TYPE_UNREGISTERED: 取消注冊
4.10.1 sendFinished
[-> BroadcastReceiver.java ::PendingResult]
public void sendFinished(IActivityManager am) { synchronized (this) { mFinished = true; ... // mOrderedHint代表發送是否為串行廣播 [見小節4.10.2] if (mOrderedHint) { am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras, mAbortBroadcast, mFlags); } else { //並行廣播, 但屬於靜態注冊的廣播, 仍然需要告知AMS. [見小節4.10.2] am.finishReceiver(mToken, 0, null, null, false, mFlags); } ... } }
此處AMP.finishReceiver,經過binder調用,進入AMS.finishReceiver方法
4.10.2 AMS.finishReceiver
public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle resultExtras, boolean resultAbort, int flags) { ... final long origId = Binder.clearCallingIdentity(); try { boolean doNext = false; BroadcastRecord r; synchronized(this) { BroadcastQueue queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0 ? mFgBroadcastQueue : mBgBroadcastQueue; r = queue.getMatchingOrderedReceiver(who); if (r != null) { //[見小節4.10.3] doNext = r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort, true); } } if (doNext) { //處理下一條廣播 r.queue.processNextBroadcast(false); } trimApplications(); } finally { Binder.restoreCallingIdentity(origId); } }
4.10.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; r.receiver = null; r.intent.setComponent(null); if (r.curApp != null && r.curApp.curReceiver == r) { r.curApp.curReceiver = null; } 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; } if (receiver == null || nextReceiver == null || receiver.applicationInfo.uid != nextReceiver.applicationInfo.uid || !receiver.processName.equals(nextReceiver.processName)) { if (mService.mServices.hasBackgroundServices(r.userId)) { r.state = BroadcastRecord.WAITING_SERVICES; return false; } } } r.curComponent = null; return state == BroadcastRecord.APP_RECEIVE || state == BroadcastRecord.CALL_DONE_RECEIVE; }
五、總結
5.1 基礎知識
1.BroadcastReceiver分為兩類:
- 靜態廣播接收者:通過AndroidManifest.xml的標簽來申明的BroadcastReceiver;
- 動態廣播接收者:通過AMS.registerReceiver()方式注冊的BroadcastReceiver, 不需要時記得調用unregisterReceiver();
2.廣播發送方式可分為三類:
類型 | 方法 | ordered | sticky |
---|---|---|---|
普通廣播 | sendBroadcast | false | false |
有序廣播 | sendOrderedBroadcast | true | false |
Sticky廣播 | sendStickyBroadcast | false | true |
3.廣播注冊registerReceiver():默認將當前進程的主線程設置為scheuler. 再向AMS注冊該廣播相應信息, 根據類型選擇加入mParallelBroadcasts或mOrderedBroadcasts隊列.
4.廣播發送processNextBroadcast():根據不同情況調用不同的處理過程:
- 如果是動態廣播接收者,則調用deliverToRegisteredReceiverLocked處理;
- 如果是靜態廣播接收者,且對應進程已經創建,則調用processCurBroadcastLocked處理;
- 如果是靜態廣播接收者,且對應進程尚未創建,則調用startProcessLocked創建進程。
5.2 流程圖
最后,通過一幅圖來總結整個廣播處理過程. 點擊查看大圖
5.2.1 並行廣播
整個過程涉及過程進程間通信, 先來說說並行廣播處理過程:
- 廣播發送端所在進程: 步驟1~2;
- system_server的binder線程: 步驟3~5;
- system_server的ActivityManager線程: 步驟6~11;
- 廣播接收端所在進程的binder線程: 步驟12~13;
- 廣播接收端所在進程的主線程: 步驟14~15,以及23;
- system_server的binder線程: 步驟24~25.
5.2.2 串行廣播
可以看出整個流程中,步驟8~15是並行廣播, 而步驟16~22則是串行廣播.那么再來說說串行廣播的處理過程.
- 廣播發送端所在進程: 步驟1~2;
- system_server的binder線程: 步驟3~5;
- system_server的ActivityManager線程:步驟6以及16~18;
- 廣播接收端所在進程的binder線程: 步驟19;
- 廣播接收端所在進程的主線程: 步驟20~22;
- system_server的binder線程: 步驟24~25.
再來說說幾個關鍵的時間點:
- enqueueClockTime: 位於步驟4 scheduleBroadcastsLocked(), 這是在system_server的binder線程.
- dispatchClockTime: 位於步驟8 deliverToRegisteredReceiverLocked(),這是在system_server的ActivityManager線程.
- finishTime : 位於步驟11 addBroadcastToHistoryLocked()之后, 這是在並行廣播向所有receivers發送完成后的時間點,而串行廣播則是一個一個發送完成才會繼續.
5.2.3 粘性廣播
對於粘性廣播,registerReceiver()會有一個返回值,數據類型為Intent。 只有粘性廣播在注冊過程過程會直接返回Intent,里面帶有相關參數。 比如常見的使用場景比如Battery廣播的注冊。
5.3 廣播處理機制
- 當發送串行廣播(ordered=true)的情況下:
- 靜態注冊的廣播接收者(receivers),采用串行處理;
- 動態注冊的廣播接收者(registeredReceivers),采用串行處理;
- 當發送並行廣播(ordered=false)的情況下:
- 靜態注冊的廣播接收者(receivers),依然采用串行處理;
- 動態注冊的廣播接收者(registeredReceivers),采用並行處理;
簡單來說,靜態注冊的receivers始終采用串行方式來處理(processNextBroadcast); 動態注冊的registeredReceivers處理方式是串行還是並行方式, 取決於廣播的發送方式(processNextBroadcast)。
靜態注冊的廣播往往其所在進程還沒有創建,而進程創建相對比較耗費系統資源的操作,所以 讓靜態注冊的廣播串行化,能防止出現瞬間啟動大量進程的噴井效應。
ANR時機:只有串行廣播才需要考慮超時,因為接收者是串行處理的,前一個receiver處理慢,會影響后一個receiver;並行廣播 通過一個循環一次性向所有的receiver分發廣播事件,所以不存在彼此影響的問題,則沒有廣播超時;
- 串行廣播超時情況1:某個廣播總處理時間 > 2* receiver總個數 * mTimeoutPeriod, 其中mTimeoutPeriod,前台隊列默認為10s,后台隊列默認為60s;
- 串行廣播超時情況2:某個receiver的執行時間超過mTimeoutPeriod;