android廣播的發送與接收流程分析(android6.0)


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服務端對象callerreceiver,都代表執行注冊廣播動作所在的進程. 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 廣播注冊小結

注冊廣播:

  1. 傳遞的參數為廣播接收者BroadcastReceiver和Intent過濾條件IntentFilter;
  2. 創建對象LoadedApk.ReceiverDispatcher.InnerReceiver,該對象繼承於IIntentReceiver.Stub;
  3. 通過AMS把當前進程的ApplicationThread和InnerReceiver對象的代理類,注冊登記到system_server進程;
  4. 當廣播receiver沒有注冊過,則創建廣播接收者隊列ReceiverList,該對象繼承於ArrayList, 並添加到AMS.mRegisteredReceivers(已注冊廣播隊列);
  5. 創建BroadcastFilter,並添加到AMS.mReceiverResolver;
  6. 將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 小結

發送廣播過程:

  1. 默認不發送給已停止(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES)的應用包;
  2. 處理各種PACKAGE,TIMEZONE等相關的系統廣播;
  3. 當為粘性廣播,則將sticky廣播增加到list,並放入mStickyBroadcasts里面;
  4. 當廣播的Intent沒有設置FLAG_RECEIVER_REGISTERED_ONLY,則允許靜態廣播接收者來處理該廣播; 創建BroadcastRecord對象,並將該對象加入到相應的廣播隊列, 然后調用BroadcastQueue的scheduleBroadcastsLocked()方法來完成的不同廣播處理:

處理方式:

  1. Sticky廣播: 廣播注冊過程處理AMS.registerReceiver,開始處理粘性廣播,見小節[2.5];
    • 創建BroadcastRecord對象;
    • 並添加到mParallelBroadcasts隊列;
    • 然后執行queue.scheduleBroadcastsLocked;
  2. 並行廣播: 廣播發送過程處理,見小節[3.4.6]
    • 只有動態注冊的mRegisteredReceivers才會並行處理;
    • 會創建BroadcastRecord對象;
    • 並添加到mParallelBroadcasts隊列;
    • 然后執行queue.scheduleBroadcastsLocked;
  3. 串行廣播: 廣播發送廣播處理,見小節[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 流程圖

最后,通過一幅圖來總結整個廣播處理過程. 點擊查看大圖

send_broadcast

5.2.1 並行廣播

整個過程涉及過程進程間通信, 先來說說並行廣播處理過程:

  1. 廣播發送端所在進程: 步驟1~2;
  2. system_server的binder線程: 步驟3~5;
  3. system_server的ActivityManager線程: 步驟6~11;
  4. 廣播接收端所在進程的binder線程: 步驟12~13;
  5. 廣播接收端所在進程的主線程: 步驟14~15,以及23;
  6. system_server的binder線程: 步驟24~25.

5.2.2 串行廣播

可以看出整個流程中,步驟8~15是並行廣播, 而步驟16~22則是串行廣播.那么再來說說串行廣播的處理過程.

  1. 廣播發送端所在進程: 步驟1~2;
  2. system_server的binder線程: 步驟3~5;
  3. system_server的ActivityManager線程:步驟6以及16~18;
  4. 廣播接收端所在進程的binder線程: 步驟19;
  5. 廣播接收端所在進程的主線程: 步驟20~22;
  6. 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 廣播處理機制

  1. 當發送串行廣播(ordered=true)的情況下:
    • 靜態注冊的廣播接收者(receivers),采用串行處理;
    • 動態注冊的廣播接收者(registeredReceivers),采用串行處理;
  2. 當發送並行廣播(ordered=false)的情況下:
    • 靜態注冊的廣播接收者(receivers),依然采用串行處理;
    • 動態注冊的廣播接收者(registeredReceivers),采用並行處理;

簡單來說,靜態注冊的receivers始終采用串行方式來處理(processNextBroadcast); 動態注冊的registeredReceivers處理方式是串行還是並行方式, 取決於廣播的發送方式(processNextBroadcast)。

靜態注冊的廣播往往其所在進程還沒有創建,而進程創建相對比較耗費系統資源的操作,所以 讓靜態注冊的廣播串行化,能防止出現瞬間啟動大量進程的噴井效應。

ANR時機:只有串行廣播才需要考慮超時,因為接收者是串行處理的,前一個receiver處理慢,會影響后一個receiver;並行廣播 通過一個循環一次性向所有的receiver分發廣播事件,所以不存在彼此影響的問題,則沒有廣播超時;

  • 串行廣播超時情況1:某個廣播總處理時間 > 2* receiver總個數 * mTimeoutPeriod, 其中mTimeoutPeriod,前台隊列默認為10s,后台隊列默認為60s;
  • 串行廣播超時情況2:某個receiver的執行時間超過mTimeoutPeriod;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM