Broadcast
實質上是提供了一種更靈活的使用Intent
的方式。java
不管是啓動Activity
,仍是Service
,其實都是經過Intent
的發送和過濾來調用應用中的功能,可是Activity
、Service
、ContentProvider
所完成的功能是固定的android
而對於BroadcastReceiver
能夠作任意的事情,同時廣播的發送和接收方式也更加豐富靈活shell
BroadcastReceiver
BroadcastReceiver
是一種很簡單的組件,甚至在ActivityThread
中都沒有管理它的數據結構。數組
BroadcastReceiver
的本質就是經過Intent
來執行應用中的一個方法,在應用中並不須要一個長期存在的對象安全
雖然應用中沒有專門的數據結構來管理BroadcastReceiver
,可是在AMS
中仍是須要的,由於BroadcastReceiver
能夠在運行時動態向AMS
註冊,AMS
中須要有數據結構來管理動態接收者markdown
BroadcastReceiver
能夠經過兩種方式接收廣播數據結構
AndroidManifest
中的<receiver/>
標籤註冊AMS
的registerReceiver()
接口註冊關於廣播使用上的知識你們能夠在官網學習:廣播基礎知識app
咱們看下BroadcastReceiver
類相關的重要定義:async
public abstract class BroadcastReceiver {
private PendingResult mPendingResult;
public abstract void onReceive(Context context, Intent intent);
public final PendingResult goAsync() {
PendingResult res = mPendingResult;
mPendingResult = null;
return res;
}
}
複製代碼
實現一個廣播接收器只須要繼承BroadcastReceiver
,而後實現它的抽象方法onReceive()
就能夠了。這也是最簡單的廣播的用法。ide
不過從BroadcastReceiver
的類定義中還有一個mPendingResult
變量和goAsync()
方法,它們有什麼做用呢?
它們主要是針對當接收到廣播後須要作一些耗時操做,並且還有可能須要返回處理結果的狀況
BroadcastReceiver
對象的onReceive()
若是長時間不返回,會引起ANR
mPendingResult
變量的存在就是爲了上述需求。而goAsync()
方法提供了獲取mPendingResult
變量的接口。
從goAsync()
方法的實現能夠看到
mPendingResult
對象的指針返回後。同時也會將mPendingResult
的值置爲null
按照官方說法:
一旦執行了
goAsync()
方法,在onReceive()
結束前,須要將mPendingResult
對象的指針傳遞到新線程中去,在新線程處理完成後必須調用mPendingResult
對象的finish()
方法來通知AMS
。
咱們看下PendingResult
的finish()
方法:
public final void finish() {
if (mType == TYPE_COMPONENT) {
final IActivityManager mgr = ActivityManager.getService();
if (QueuedWork.hasPendingWork()) {
QueuedWork.queue(new Runnable() {
@Override public void run() {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast after work to component " + mToken);
sendFinished(mgr);
}
}, false);
} else {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to component " + mToken);
sendFinished(mgr);
}
} else if (mOrderedHint && mType != TYPE_UNREGISTERED) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to " + mToken);
final IActivityManager mgr = ActivityManager.getService();
sendFinished(mgr);
}
}
public void sendFinished(IActivityManager am) {
synchronized (this) {
...
try {
...
if (mOrderedHint) {
am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
mAbortBroadcast, mFlags);
} else {
am.finishReceiver(mToken, 0, null, null, false, mFlags);
}
} catch (RemoteException ex) {
}
}
}
複製代碼
核心操做就是調用AMS
的finishReceiver()
方法,這纔是當前廣播接收器的結束的標誌。
正常狀況下(沒有執行過goAsync()
)當onReceive()
調用完成後,AMS
檢測到mPendingResult
不爲空,便會自動執行finish()
方法,而對於執行過goAsync()
的廣播接收器,AMS
便不會主動執行finish()
了
這個
finish()
方法很重要,本章最後也有它的身影
從廣播的發送方式來劃分,有4類廣播。
Context
中的方法sendBroadcast()
和sendBroadcastAsUser()
發送的廣播屬於普通廣播。
Context
中的方法sendOrderedBroadcast()
和sendOrderedBroadcastAsUser()
發送的廣播屬於有序廣播。
-1000
-1000
,但實際上沒有明確的數值限定,能夠到int
最大值intent-filter
的android:priority
屬性來控制Context
中的方法sendStickyBroadcast()
和sendOrderedBroadcastAsUser()
發送的廣播屬於粘性廣播。
Android 9
上,這兩個接口被標記爲了Deprecated
Framework
中的使用,咱們看個官網的例子:IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
// 對於一個粘性廣播來講,註冊監聽時即可以獲得當前電池狀態的 Intent
Intent batteryStatus = context.registerReceiver(null, ifilter);
複製代碼
LocalBroadcastManager.sendBroadcast
發送的廣播屬於本地廣播
在AMS
中,全部註冊的廣播接收者都放在成員變量mRegisteredReceivers
中,定義以下:
final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();
複製代碼
mRegisteredReceivers
是一個HashMap
,其中
key
爲接收者的IBinder
對象
value
爲接收者的對象ReceiverList
IntentFilter
,因此ReceiverList
是一個數組final class ReceiverList extends ArrayList<BroadcastFilter> 複製代碼
BroadcastFilter
則是繼承了IntentFilter
,定義以下:final class BroadcastFilter extends IntentFilter {
final ReceiverList receiverList; // 所屬 receiver 的引用
final String packageName; // 所在應用的包名
final String requiredPermission; // 發送廣播時須要聲明的權限字符串
final int owningUid; // 所在應用的 uid
final int owningUserId; // 所在應用的 userid
...
}
複製代碼
ReceiverList
的關鍵定義以下:
final class ReceiverList extends ArrayList<BroadcastFilter> implements IBinder.DeathRecipient {
final ActivityManagerService owner;
public final IIntentReceiver receiver; // 用戶進程中定義的 IntentReceiver
public final ProcessRecord app; // 所屬用戶進程的 ProcessRecord 對象
public final int pid; // 所屬用戶進程的pid
public final int uid; // 所屬用戶進程的uid
public final int userId; // 用戶id
BroadcastRecord curBroadcast = null; //
boolean linkedToDeath = false; // 是否註冊了 binder 死亡監聽
}
複製代碼
發送廣播時,AMS
中收到的廣播消息首先會保存在mBroadcastQueues
對象中,而後再發送給用戶進程中的接收者。mBroadcastQueues
是一個只有兩個元素的數組,定義以下:
final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[2];
複製代碼
此外,AMS
中還定義了兩個變量:
BroadcastQueue mFgBroadcastQueue;
BroadcastQueue mBgBroadcastQueue;
複製代碼
AMS
在構造方法中將這兩個變量和mBroadcastQueues
集合進行了關聯:
public ActivityManagerService(Context systemContext) {
...
mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
"foreground", BROADCAST_FG_TIMEOUT, false);
mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
"background", BROADCAST_BG_TIMEOUT, true);
mBroadcastQueues[0] = mFgBroadcastQueue;
mBroadcastQueues[1] = mBgBroadcastQueue;
...
}
複製代碼
mFgBroadcastQueue
用來保存帶有FLAG_RECEIVER_FOREGROUND
標誌的廣播,它要求接收者進程以foreground
的優先級運行,這樣執行的更快。mBgBroadcastQueue
中咱們看下BroadcastQueue
類的主要結構:
public final class BroadcastQueue {
final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>();
final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();
}
複製代碼
mParallelBroadcasts
用來保存全部的普通廣播mOrderedBroadcasts
用來保存全部的有序廣播粘性廣播在哪裏呢?
系統中全部的粘性廣播都保存在AMS
的成員變量mStickyBroadcasts
中,定義以下:
final SparseArray<ArrayMap<String, ArrayList<Intent>>> mStickyBroadcasts =
new SparseArray<ArrayMap<String, ArrayList<Intent>>>();
複製代碼
mStickyBroadcasts
是一個SparseArray
類型的數組,使用用戶Id
做爲索引,保存的是ArrayMap
對象ArrayMap
對象儲存的是某個用戶發送的全部的粘性廣播,每條記錄以Intent
的action
字符串做爲索引,保存的內容是一個ArrayList
對象ArrayList
對象其中儲存了包含該action
的Intent
動態註冊是經過接口registerReceiver()
完成的。應用註冊receiver
時,並非直接調用AMS
的接口來完成的,而是經過Context
類中的方法,由於AMS
的接口須要提供應用的ApplicationThread
類的IBinder
對象來做爲參數,應用中獲得這個對象比較麻煩。
Context
中的registerReceiver()
最終調用的是ContextImpl
的registerReceiverInternal()
方法,代碼以下:
class ContextImpl{
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId, IntentFilter filter, String broadcastPermission, Handler scheduler, Context context, int flags) {
...
try {
final Intent intent = ActivityManager.getService().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
broadcastPermission, userId, flags);
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
intent.prepareToEnterProcess();
}
return intent;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
複製代碼
registerReceiverInternal()
方法最終調用的是AMS
的registerReceiver()
方法,代碼以下:
public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId, int flags) {
// 確保不是 isolated 進程
enforceNotIsolatedCaller("registerReceiver");
ArrayList<Intent> stickyIntents = null;
ProcessRecord callerApp = null;
final boolean visibleToInstantApps
= (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
int callingUid;
int callingPid;
boolean instantApp;
synchronized(this) {
...
// 從註冊信息中獲取 action 信息
Iterator<String> actions = filter.actionsIterator();
if (actions == null) {
ArrayList<String> noAction = new ArrayList<String>(1);
noAction.add(null);
actions = noAction.iterator();
}
// 獲取 user ID
int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
// 循環遍歷 action
while (actions.hasNext()) {
String action = actions.next();
// 遍歷每一個userID下的粘性廣播Map
for (int id : userIds) {
// 獲取特定userID下的粘性廣播Map
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
if (stickies != null) {
// 從Map中查找集合中符合當前action信息的Intent集合
ArrayList<Intent> intents = stickies.get(action);
if (intents != null) {
if (stickyIntents == null) {
stickyIntents = new ArrayList<Intent>();
}
// 添加到 stickyIntents 集合中
stickyIntents.addAll(intents);
}
}
}
}
}
ArrayList<Intent> allSticky = null;
if (stickyIntents != null) {
// 粘性廣播不爲空
final ContentResolver resolver = mContext.getContentResolver();
// 查找全部符合符合當前請求的Intent
for (int i = 0, N = stickyIntents.size(); i < N; i++) {
Intent intent = stickyIntents.get(i);
...
if (filter.match(resolver, intent, true, TAG) >= 0) {
if (allSticky == null) {
allSticky = new ArrayList<Intent>();
}
allSticky.add(intent);
}
}
}
// The first sticky in the list is returned directly back to the client.
Intent sticky = allSticky != null ? allSticky.get(0) : null;
// 若是註冊時傳入的 receiver 爲空
// 此處直接返回 sticky 對象
if (receiver == null) {
return sticky;
}
synchronized (this) {
if (callerApp != null && (callerApp.thread == null
|| callerApp.thread.asBinder() != caller.asBinder())) {
// Original caller already died
return null;
}
// 檢查註冊的 receiver 是否已經註冊過了
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
// rl爲空說明沒有註冊過
// 新建對象
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
if (rl.app != null) {
// 若是指定了進程對象,則把receiver保存在進程對象中
// 方便進程銷燬時能及時釋放該對象
final int totalReceiversForApp = rl.app.receivers.size();
if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {
throw new IllegalStateException(...);
}
rl.app.receivers.add(rl);
} else {
// 若是沒有指定進程對象,則註冊receiver的死亡通知
try {
receiver.asBinder().linkToDeath(rl, 0);
} catch (RemoteException e) {
return sticky;
}
rl.linkedToDeath = true;
}
mRegisteredReceivers.put(receiver.asBinder(), rl);// 保存新建的 rl
}
...
// 下面主要是針對 receiver 重複註冊的狀況
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId, instantApp, visibleToInstantApps);
if (rl.containsFilter(filter)) {
// 已經包含了本次提交filter,簡單打印,不作其餘處理
Slog.w(TAG, "Receiver with filter " + filter
+ " already registered for pid " + rl.pid
+ ", callerPackage is " + callerPackage);
} else {
// 未包含本次提交的filter,添加到集合中
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadcast");
}
mReceiverResolver.addFilter(bf);
}
// 繼續處理粘性廣播部分
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 中的標誌獲取發送隊列(bg仍是fg)
BroadcastQueue queue = broadcastQueueForIntent(intent);
// 建立新的廣播對象
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, -1, -1, false, null, null, OP_NONE, null, receivers,
null, 0, null, null, false, true, true, -1);
// 將廣播加入隊列
queue.enqueueParallelBroadcastLocked(r);
// 發送 Intent 到指定進程
queue.scheduleBroadcastsLocked();
}
}
return sticky;
}
}
複製代碼
registerReceiver()
方法看上去比較複雜,其實不少都是針對粘性(sticky
)廣播的:
若是沒有處理粘性(sticky
)廣播,只須要檢查receiver
是否已經註冊
receiver
的對象ReceiverList
,並把它添加到mRegisteredReceivers
集合中receiver
能夠重複註冊,只要pid、``uid
和userid
相同就能夠
receiver
增長新的IntentFilter
而對於粘性(sticky
)廣播
registerReceiver()
時參數receiver
爲null
,則馬上返回找到的第一個粘性廣播的Intent
Intent
匹配的粘性廣播,並經過BroadcastQueue
來發送咱們再來看下廣播的發送過程
應用發送廣播調用的是Context
類中的方法,發送廣播的方法雖然不少,最後都是調用AMS
的broadcastIntent()
方法。
broadcastIntent()
方法簡單檢查了調用者的權限後,轉調內部方法broadcastIntentLocked()
來完成廣播發送。
broadcastIntentLocked()
方法會
先檢查要廣播的Intent
Intent
,則調用相應的方法處理Intent
加入AMS
的粘性廣播列表中最後查找全部的接收者,逐個調用它們
廣播發送的時序圖以下:
AMS.broadcastIntentLocked
咱們看下具體實現:
final int broadcastIntentLocked(...) {
intent = new Intent(intent);
...
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
ALLOW_NON_FULL, "broadcast", callerPackage);
// 檢查發送廣播的用戶是否正在運行
if (userId != UserHandle.USER_ALL && !mUserController.isUserOrItsParentRunning(userId)) {
if ((callingUid != SYSTEM_UID
|| (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
&& !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
}
}
final String action = intent.getAction();
...
// 檢查廣播是否爲 protected
final boolean isProtectedBroadcast;
try {
isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception", e);
return ActivityManager.BROADCAST_SUCCESS;
}
// 確認發送廣播的進程是否爲 system
final boolean isCallerSystem;
switch (UserHandle.getAppId(callingUid)) {
case ROOT_UID:
case SYSTEM_UID:
case PHONE_UID:
case BLUETOOTH_UID:
case NFC_UID:
case SE_UID:
isCallerSystem = true;
break;
default:
isCallerSystem = (callerApp != null) && callerApp.persistent;
break;
}
if (!isCallerSystem) {
if (isProtectedBroadcast) {
// 不是system進程,可是發送的廣播倒是 protected 的狀況
// 拋出安全異常
...
throw new SecurityException(msg);
} else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
// 不是 system 進程,也不是 protected 廣播
// 可是,有一些特殊的廣播仍是不能發送,這裏作一些限制
if (callerPackage == null) {
...
throw new SecurityException(msg);
} else if (intent.getComponent() != null) {
if (!intent.getComponent().getPackageName().equals(
callerPackage)) {
String msg = "Permission Denial: not allowed to send broadcast "
+ action + " to "
+ intent.getComponent().getPackageName() + " from "
+ callerPackage;
...
throw new SecurityException(msg);
}
} else {
// Limit broadcast to their own package.
intent.setPackage(callerPackage);
}
}
}
if (action != null) {
// 從 SystemConfig 中查詢當前 action 是否在 allow-implicit-broadcast 標籤中
// 就是查查當前 action 是否支持隱式廣播
if (getBackgroundLaunchBroadcasts().contains(action)) {
...
// 若是是,增長一個Flag標記
// 這個標記就代表這個廣播能夠做爲隱式廣播發送
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
}
switch (action) {
// 檢查處理一些特殊的 action
// 這部分主要是檢查和 PMS 有關的一些操做
case Intent.ACTION_UID_REMOVED:
case Intent.ACTION_PACKAGE_REMOVED:
case Intent.ACTION_PACKAGE_CHANGED:
...
// 若是這個廣播時從 PMS 來的,並且是關於應用刪除或應用變化
// 須要從 task 中移除全部和該應用管理的 Activity
break;
...
case "com.android.launcher.action.INSTALL_SHORTCUT":
// As of O, we no longer support this broadcasts, even for pre-O apps.
// Apps should now be using ShortcutManager.pinRequestShortcut().
Log.w(TAG, "Broadcast " + action
+ " no longer supported. It will not be delivered.");
return ActivityManager.BROADCAST_SUCCESS;
}
...
}
// 對於粘性廣播
if (sticky) {
// 檢查廣播發送方是否聲明瞭 android.permission.BROADCAST_STICKY 權限
if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
callingPid, callingUid)
!= PackageManager.PERMISSION_GRANTED) {
...
throw new SecurityException(msg);
}
if (requiredPermissions != null && requiredPermissions.length > 0) {
// 發送粘性廣播不能指定 permission
return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
}
if (intent.getComponent() != null) {
// 粘性廣播不能指定特定組件名
throw new SecurityException(
"Sticky broadcasts can't target a specific component");
}
if (userId != UserHandle.USER_ALL) {
// 若是廣播不是發給全部用戶,先檢查是否存在一個發給全部用戶的相同的廣播
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(UserHandle.USER_ALL);
if (stickies != null) {
ArrayList<Intent> list = stickies.get(intent.getAction());
if (list != null) {
int N = list.size();
int i;
for (i=0; i<N; i++) {
if (intent.filterEquals(list.get(i))) {
// 檢測到存在相同的廣播,拋出異常
throw new IllegalArgumentException(
"Sticky broadcast " + intent + " for user "
+ userId + " conflicts with existing global broadcast");
}
}
}
}
}
// 將廣播保存到 mStickyBroadcasts 中
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
if (stickies == null) {
stickies = new ArrayMap<>();
mStickyBroadcasts.put(userId, stickies);
}
// 添加 Intent 信息列表
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))) {
// 若是 Intent 已經存在,覆蓋
list.set(i, new Intent(intent));
break;
}
}
if (i >= stickiesCount) {
list.add(new Intent(intent));
}
}
int[] users;
if (userId == UserHandle.USER_ALL) {
// 廣播給全部用戶的狀況,獲取全部的用戶id
users = mUserController.getStartedUserArray();
} else {
// 廣播給特定用戶
users = new int[] {userId};
}
// 計算全部接收該 Intent 的 receiver
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
// 若是 Intent 中沒有指定 FLAG_RECEIVER_REGISTERED_ONLY
// 收集靜態接收者
receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}
if (intent.getComponent() == null) {
// 若是沒有指定 Component,則查找匹配該 Intent 的全部 receiver
if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
// 針對發送給全部用戶的廣播,而且發送廣播的 user 是 shell
for (int i = 0; i < users.length; i++) {
// 遍歷 userID
...
// 從 mReceiverResolver 中查找,動態註冊的廣播接收者都在這裏
List<BroadcastFilter> registeredReceiversForUser = mReceiverResolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, users[i]);
if (registeredReceivers == null) {
registeredReceivers = registeredReceiversForUser;
} else if (registeredReceiversForUser != null) {
registeredReceivers.addAll(registeredReceiversForUser);
}
}
} else {
registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, userId);
}
}
final boolean replacePending =
(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) {
// 若是不是有序廣播,也就是普通廣播的狀況
if (isCallerSystem) {
checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
isProtectedBroadcast, registeredReceivers);
}
// 獲取發送隊列
final BroadcastQueue queue = broadcastQueueForIntent(intent);
// 建立 BroadcastRecord 對象
BroadcastRecord r = new BroadcastRecord(...);
...
if (!replaced) {
queue.enqueueParallelBroadcastLocked(r); // 加入到並行隊列中
queue.scheduleBroadcastsLocked(); // 發送廣播
}
registeredReceivers = null;
NR = 0;
}
int ir = 0;
if (receivers != null) {
// 說明存在靜態註冊的接收者
...
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 {
// Skip to the next ResolveInfo in the final list.
it++;
curt = null;
}
}
}
// 在隊列中加入剩下的動態接受者
while (ir < NR) {
if (receivers == null) {
receivers = new ArrayList();
}
receivers.add(registeredReceivers.get(ir));
ir++;
}
...
if ((receivers != null && receivers.size() > 0) || resultTo != null) {
// 獲取廣播發送隊列
BroadcastQueue queue = broadcastQueueForIntent(intent);
// 建立廣播對象
BroadcastRecord r = new BroadcastRecord(...);
...
final BroadcastRecord oldRecord =
replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
if (oldRecord != null) {
// 若是存在舊的廣播,調用 performReceiveLocked 執行廣播
if (oldRecord.resultTo != null) {
final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);
try {
// 這個方法就會調用到 onReceived()
oldQueue.performReceiveLocked(...);
} catch (RemoteException e) {
...
}
}
} else {
queue.enqueueOrderedBroadcastLocked(r); // 將廣播加入到order隊列
queue.scheduleBroadcastsLocked(); // 發送廣播
}
}
...
return ActivityManager.BROADCAST_SUCCESS;
}
複製代碼
broadcastIntentLocked()
方法比較長,咱們再簡單梳理下:
PMS
中發出的有關應用安裝變化相關的廣播permission
,並且Intent
必須指定Component
mStickyBroadcasts
集合中BroadcastRecord
對象並添加到有序廣播隊列中scheduleBroadcastsLocked()
發送廣播從上面的代碼實現上能夠看到,不管哪一種廣播,靜態接收者之間必定會排序,並且相同優先級下,靜態接收者會排在動態接收者以前。
爲何靜態接收者必定要放到有序隊列呢?
對於靜態接收者來講,它所屬的進程可能已經在運行,也可能沒有。若是進程沒有運行,就須要先啓動它。首先進程的啓動是一個耗時過程,並且啓動有可能失敗,這個過程只能逐一處理,不能簡單的羣發消息。
到這裏,廣播接收者和廣播內容都已經檢查準備好了,咱們繼續學習scheduleBroadcastsLocked()
廣播發送的過程
BroadcastQueue.scheduleBroadcastsLocked
scheduleBroadcastsLocked()
方法只是發送了一個BROADCAST_INTENT_MSG
消息,代碼以下:
public void scheduleBroadcastsLocked() {
...
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
複製代碼
BROADCAST_INTENT_MSG
消息的處理是調用processNextBroadcast()
方法
case BROADCAST_INTENT_MSG: {
...
processNextBroadcast(true);
} break;
final void processNextBroadcast(boolean fromMsg) {
synchronized (mService) {
processNextBroadcastLocked(fromMsg, false);
}
}
複製代碼
調用到了processNextBroadcastLocked()
方法。這個方法比較長,咱們簡要分析:
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
BroadcastRecord r;
...
// 循環處理 mParallelBroadcasts 集合中的消息
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
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
}
addBroadcastToHistoryLocked(r);
}
// 接下來處理 mPendingBroadcast 集合
// 這個集合存放的是等待進程啓動的廣播
if (mPendingBroadcast != null) {
...
boolean isDead;
if (mPendingBroadcast.curApp.pid > 0) {
synchronized (mService.mPidsSelfLocked) {
ProcessRecord proc = mService.mPidsSelfLocked.get(
mPendingBroadcast.curApp.pid);
isDead = proc == null || proc.crashing;
}
} else {
final ProcessRecord proc = mService.mProcessNames.get(
mPendingBroadcast.curApp.processName, mPendingBroadcast.curApp.uid);
isDead = proc == null || !proc.pendingStart;
}
if (!isDead) {
// It's still alive, so keep waiting
return;
} else {
Slog.w(TAG, "pending app ["
+ mQueueName + "]" + mPendingBroadcast.curApp
+ " died before responding to broadcast");
mPendingBroadcast.state = BroadcastRecord.IDLE;
mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
mPendingBroadcast = null;
}
}
// 處理 mOrderedBroadcasts 中的廣播
boolean looped = false;
do {
...
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();
// forground 的 mTimeoutPeriod 超時是 10*1000
// bgground 的 mTimeoutPeriod 超時是 60*1000
if ((numReceivers > 0) && (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
// 若是超時則終止廣播
...
broadcastTimeoutLocked(false); // forcibly finish this broadcast
forceReceive = true;
r.state = BroadcastRecord.IDLE;
}
}
...
if (r.receivers == null || r.nextReceiver >= numReceivers
|| r.resultAbort || forceReceive) {
// 沒有多餘的 receiver 了
if (r.resultTo != null) {
try {
...
// 把廣播結果傳遞給發送廣播的進程
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent), r.resultCode,
r.resultData, r.resultExtras, false, false, r.userId);
r.resultTo = null;
} catch (RemoteException e) {
r.resultTo = null;
...
}
}
...
}
} while (r == null);
...
if (nextReceiver instanceof BroadcastFilter) {
BroadcastFilter filter = (BroadcastFilter)nextReceiver;
...
// 發送給接收者進程
deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
if (r.receiver == null || !r.ordered) {
...
// 已經處理完成的狀況
r.state = BroadcastRecord.IDLE;
// 處理下一條廣播
scheduleBroadcastsLocked();
} else {
if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
scheduleTempWhitelistLocked(filter.owningUid,
brOptions.getTemporaryAppWhitelistDuration(), r);
}
}
return;
}
...
ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
info.activityInfo.applicationInfo.uid, false);
...
if (app != null && app.thread != null && !app.killed) {
// 若是是靜態接收者,而且接收者對應的進程已經啓動的狀況
try {
app.addPackage(info.activityInfo.packageName,
info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
// 調用 processCurBroadcastLocked 通知 receiver
processCurBroadcastLocked(r, app, skipOomAdj);
// 直接返回
return;
}
...
}
...
// 走到這裏說明進程沒有啓動,先調用 startProcessLocked 啓動進程
if ((r.curApp=mService.startProcessLocked(...)) == null) {
....
// 若是進程啓動失敗,處理下一條廣播
scheduleBroadcastsLocked();
r.state = BroadcastRecord.IDLE;
return;
}
mPendingBroadcast = r;
mPendingBroadcastRecvIndex = recIdx;
}
複製代碼
processNextBroadcastLocked()
方法也只是對要發送的廣播接收者的集合進行的遍歷發送處理,真正通知到應用的部分是在deliverToRegisteredReceiverLocked()
方法中,咱們具體看下。
BroadcastQueue.deliverToRegisteredReceiverLocked
方法以下:
private void deliverToRegisteredReceiverLocked(BroadcastRecord r, BroadcastFilter filter, boolean ordered, int index) {
...
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
...
}
void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
// Send the intent to the receiver asynchronously using one-way binder calls.
if (app != null) {
if (app.thread != null) {
...
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.repProcState);
...
}
} else {
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
}
}
複製代碼
咱們已經在performReceiveLocked
方法中明顯看到app.thread
字樣了,這也就意味着開始去調用應用進程中的接口了,也就是ActivityThread
中的scheduleRegisteredReceiver()
接口,以下:
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent, int resultCode, String dataStr, Bundle extras, boolean ordered, boolean sticky, int sendingUser, int processState) throws RemoteException {
...
receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
sticky, sendingUser);
}
複製代碼
ActivityThread
調用的是IIntentReceiver
的performReceive()
方法
IIntentReceiver
是一個AIDL
,跟蹤實現是在LoadedApk
中,具體的裝配過程是在ContextImpl
初始化時完成的
咱們看下在LoadedApk
中的關鍵定義
LoadedApk.performReceive
代碼以下:
class LoadedApk{
static final class ReceiverDispatcher {
final static class InnerReceiver extends IIntentReceiver.Stub {
...
@Override
public void performReceive(...) {
final LoadedApk.ReceiverDispatcher rd;
...
// 調用內部的 performReceive() 方法
rd.performReceive(...);
...
}
}
...
public void performReceive(...) {
final Args args = new Args(...);
...
// 此處重點是執行經過 Args.getRunnable() 獲取的 Runnable 對象
// Runnable 對象中執行了 onReceive() 方法回調
if (intent == null || !mActivityThread.post(args.getRunnable())) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManager.getService();
...
args.sendFinished(mgr);
}
}
}
final class Args extends BroadcastReceiver.PendingResult {
...
public final Runnable getRunnable() {
return () -> {
final BroadcastReceiver receiver = mReceiver;
...
try {
...
// onReceive 回調
receiver.onReceive(mContext, intent);
}
...
if (receiver.getPendingResult() != null) {
// mPendingResult 不爲空,自動執行 finish()
finish();
}
};
}
}
}
}
複製代碼
這樣一個廣播的發送就結束了。。。
AMS
的章節終因而磕磕絆絆的學完了,不少細節沒有掌握,好在總體流程上暫時還留有印象。留此筆記方便複習
下一篇學習Android的圖形顯示系統
,加油💪