---
title: '四大組件 - Broadcast'
disqus: kyleAlien
---
四大組件 - Broadcast
===
## OverView of Content
[TOC]
## Broadcast 註冊
廣播接收者已可依照自己的興趣,動態 or 靜態去註冊想要接收到的訊息
1. 靜態廣播是設定在 AndroidManifest 中
```xml=
// AndroidManifest.xml
<receiver android:name=".TestBroadcast"
android:enabled="true">
<intent-filter>
<action android:name="com.hello.world"/>
</intent-filter>
</receiver>
```
2. 動態廣播是在 Activity 中接收
```java=
// Activity 中
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 想收到 ALARM_SERVICE 的訊息
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("Hello", intent.getAction());
}
}, new IntentFilter(Context.ALARM_SERVICE));
}
```
### 靜態註冊
* 在 PackageManager 安裝 APK 時,會分析 APK 中的 AndroidManifest 訊息,並保存起來,其中就有包含 Broadcast 訊息
* 這裡就不詳細分析
### APP 動態註冊 - registerReceiver
* 從 Activity 使用 registerReceiver 註冊廣播時,會先呼叫到 [ContextWrapper](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/content/ContextWrapper.java)#registerReceiver,而 ContextWrapper 是裝飾模式,實作類是 [**ContextImpl**](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/ContextImpl.java)
```java=
// ContextWrapper.java
@Override
public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter) {
// mBase 的實作類是 ContextImpl
return mBase.registerReceiver(receiver, filter);
}
// ----------------------------------------------------------------------------
// ContextImpl.java
class ContextImpl extends Context {
final @NonNull LoadedApk mPackageInfo;
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
return registerReceiver(receiver, filter, null, null);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
// 分析 registerReceiverInternal
return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext(), 0);
}
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
// @ 重點類 IIntentReceiver
IIntentReceiver rd = null;
if (receiver != null) {
// mPackageInfo 是 LoadedApk 類
if (mPackageInfo != null && context != null) {
// 可以設定接收的 Handler
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
// 透過 LoadedApk 取得 IIntentReceiver
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
// 手動 new 出一個 IIntentReceiver
// 等等查看 getIIntentReceiver 方法
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
try {
// 透過 ActivityManager 取得代理類,訪問 AMS#registerReceiverWithFeature 方法
final Intent intent = ActivityManager.getService().registerReceiverWithFeature(
mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(),
AppOpsManager.toReceiverId(receiver), rd, filter, broadcastPermission, userId,
flags);
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent),
getAttributionSource());
}
return intent;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
```
> 
* 從上面 ,可以看出兩個重點
1. 創建 [**LoadedApk**](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/LoadedApk.java)#ReceiverDispatcher 類,它會 ^1.^ 保存本地 receiver 接收者、^2.^ **創建一個 IIntentReceiver.Stub 類用來與 AMS 通訊**
```java=
// LoadedApk#ReceiverDispatcher.java
static final class ReceiverDispatcher {
final IIntentReceiver.Stub mIIntentReceiver;
final BroadcastReceiver mReceiver;
final static class InnerReceiver extends IIntentReceiver.Stub {
... 省略
}
ReceiverDispatcher(BroadcastReceiver receiver, Context context,
Handler activityThread, Instrumentation instrumentation,
boolean registered) {
// 創建 InnerReceiver,用來跟 AMS 通訊
mIIntentReceiver = new InnerReceiver(this, !registered);
// 保存接收者
mReceiver = receiver;
... 省略部分
}
IIntentReceiver getIIntentReceiver() {
return mIIntentReceiver;
}
}
```
> 
2. 透過 ActivityManager 取得代理類,訪問 AMS#**registerReceiverWithFeature** 方法
> 下一小節詳細介紹
* 從這裡可以知道傳入 AMS 中的對象是 InnerReceiver 類
### [AMS](https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/services/core/java/com/android/server/am/ActivityManagerService.java) 註冊廣播 - registerReceiver
* 目前到了系統進程 (SystemServer 進程) 中的 AMS 來註冊傳入的 **IntentFilter**,首先第一步是先分析傳入的 IntentFilter 相對應的 黏性廣播
1. 首先找到呼叫者進程 (ProcessRecord) 確定,呼叫者進程還存在
2. 遍歷傳入的 IntentFilter 中的 Action 列表 (String 列表)
3. 透過 AMS 中的 mStickyBroadcasts,收集所有跟目前傳入的 IntentFilter 有關係的 Intent
4. 取得 ContentResolver 與傳入的 IntentFilter 比對,若有符合就加入 allSticky 列表
```java=
// ActivityManagerService.java
/**
* 每個用戶活躍的黏性廣播狀態
* 外部 SparseArray
* Key: 用戶 ID (UserHandle.USER_ALL 發送給所有使用者)
* Value: ArrayMap
* 內部 ArrayMap
* Key: 動作 Action Intent
* Value: 所有廣播 Intent
*/
final SparseArray<ArrayMap<String, ArrayList<Intent>>> mStickyBroadcasts =
new SparseArray<ArrayMap<String, ArrayList<Intent>>>();
public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
String callerFeatureId, String receiverId, IIntentReceiver receiver,
IntentFilter filter, String permission, int userId, int flags) {
enforceNotIsolatedCaller("registerReceiver");
ArrayList<Intent> stickyIntents = null;
// 呼叫者的進程
ProcessRecord callerApp = null;
...
synchronized(this) {
if (caller != null) {
// 1. 使用者 ProcessRecord
callerApp = getRecordForAppLOSP(caller);
if (callerApp == null) {
// 無法取得呼叫者近程,就會拋出
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when registering receiver " + receiver);
}
...
callingUid = callerApp.info.uid;
callingPid = callerApp.getPid();
} else {
callerPackage = null;
// 呼叫者 Uid、Pid
callingUid = Binder.getCallingUid();
callingPid = Binder.getCallingPid();
}
...
// 傳入的 IntentFilter 中取得 actions 列表
Iterator<String> actions = filter.actionsIterator();
if (actions == null) {
ArrayList<String> noAction = new ArrayList<String>(1);
noAction.add(null);
actions = noAction.iterator();
}
// Collect stickies of users
int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
// 2. 遍歷使用者傳入的 IntentFilter 列表的 Action
while (actions.hasNext()) {
// 使用者設定的 Actions
String action = actions.next();
for (int id : userIds) {
// 透過 id,搜尋全域 mStickyBroadcasts,找到有相關的 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>();
}
// 3. 收集該 Intentfilter 所有要廣播的對象
stickyIntents.addAll(intents);
}
}
}
}
}
ArrayList<Intent> allSticky = null;
if (stickyIntents != null) {
// ContentResolver 是通過 ContentProvider 來獲取其他與應用程式共享的資料
final ContentResolver resolver = mContext.getContentResolver();
// 變歷蒐集到的黏性廣播
for (int i = 0, N = stickyIntents.size(); i < N; i++) {
Intent intent = stickyIntents.get(i);
// 不必立即廣播的就先忽略
if (instantApp &&
(intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
continue;
}
// 4. IntentFilter 比對 Provider,若比對回傳 >= 0 代表有 match
if (filter.match(resolver, intent, true, TAG) >= 0) {
if (allSticky == null) {
allSticky = new ArrayList<Intent>();
}
allSticky.add(intent);
}
}
}
... 省略部分
}
```
> 
* AMS 收集完黏性廣播列表後做的事情如下 (目前還在同樣的 Function 中)
1. 判斷原進程是否已經死亡,若已經死亡,則不繼續進行
2. 透過傳入的 IIntentReceiver (APP 端與 AMS 通訊的 IBinder) 在 AMS 的全域變數 mRegisteredReceivers 中取得 ReceiverList 對象
:::info
* AMS 會保存所有廣播接收者到 mRegisteredReceivers,這樣在接收到廣播時就可以找到相對的 BroadcastFilter 對象
:::
3. 若沒有 ReceiverList 代表是第一次註冊該廣播,手動 new ReceiverList 對象
:::info
* ReceiverList 用來儲存廣播接收者 (IIntentReceiver)
:::
4. 創建 BroadcastFilter 對象,並 **把 ReceiverList 作為參數傳入 (相互持有)**,最後再把自己添加進 ReceiverList 列表
5. 對全域的 mReceiverResolver 添加 BroadcastFilter,**這樣當 AMS 收到廣播時,就可以找到對應的廣播接收者 (BroadcastFilter)**
> 
6. 將前面收集的所有黏性廣播,添加進相對應的 BroadcastQueue,並發送
```java=
// ActivityManagerService.java
// 收集所有的 IIntentReceiver (Key)
final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();
// mReceiverResolver 儲存所有已註冊的 Receiver (BroadcastFilter 對象)
final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
= new IntentResolver<BroadcastFilter, BroadcastFilter>() {
@Override
protected boolean allowFilterResult(
BroadcastFilter filter, List<BroadcastFilter> dest) {
IBinder target = filter.receiverList.receiver.asBinder();
for (int i = dest.size() - 1; i >= 0; i--) {
if (dest.get(i).receiverList.receiver.asBinder() == target) {
return false;
}
}
return true;
}
@Override
protected BroadcastFilter newResult(BroadcastFilter filter, int match, int userId) {
if (userId == UserHandle.USER_ALL || filter.owningUserId == UserHandle.USER_ALL
|| userId == filter.owningUserId) {
return super.newResult(filter, match, userId);
}
return null;
}
@Override
protected IntentFilter getIntentFilter(@NonNull BroadcastFilter input) {
return input;
}
@Override
protected BroadcastFilter[] newArray(int size) {
return new BroadcastFilter[size];
}
@Override
protected boolean isPackageForFilter(String packageName, BroadcastFilter filter) {
return packageName.equals(filter.packageName);
}
};
public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
String callerFeatureId, String receiverId, IIntentReceiver receiver,
IntentFilter filter, String permission, int userId, int flags) {
... 前半段在收集需要的黏性廣播
// The first sticky in the list is returned directly back to the client.
Intent sticky = allSticky != null ? allSticky.get(0) : null;
if (receiver == null) {
return sticky;
}
synchronized (this) {
IApplicationThread thread;
if (callerApp != null && ((thread = callerApp.getThread()) == null
|| thread.asBinder() != caller.asBinder())) {
// 1. 原進程已經死亡直接返回
return null;
}
// 2. 透過 IIntentReceiver 嘗試在 mRegisteredReceivers 取得緩存
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
// 若沒有緩存,則創建 ReceiverList 對象
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
... 省略部分
// 以 IIntentReceiver 為 Key 儲存 ReceiverList
mRegisteredReceivers.put(receiver.asBinder(), rl);
} /* 省略其他 if else */
...
// 3. 創建一個廣播過濾器 (BroadcastFilter)
// 接收 rl 參數 (相互持有)
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps);
// 查看 ReceiverList 是否有使用者傳入的 IntentFilter
if (rl.containsFilter(filter)) {
... Log 訊息
} else {
// 4. 添加動態廣播
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadcast");
}
// 5. 對全域的 IntentResolver 添加 BroadcastFilter
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);
// Queue 排序
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, null, -1, -1, false, null, null, null, OP_NONE, null, receivers,
null, 0, null, null, false, true, true, -1, false, null,
false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
// 6. 將 Broadcast 放入 Queue 排序列表尾端
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
}
return sticky;
}
}
```
> 
## Broadcast 發送
* 廣播的發送有許多種方式
1. 無序廣播
```java=
activity.sendBroadcast(new Intent("Hello"));
```
2. 有序廣播
```java=
activity.sendOrderedBroadcast(new Intent("World"), "TEST");
```
3. 黏性廣播
### 發送無序廣播 - 整理 Receiver
* sendBroadcast 方法第一個觸發的類是 ContextWrapper,但上面有介紹過 ContextWrapper 是一個裝飾類這裡就跳過它,到實作 [**ContextImpl 類**](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/ContextImpl.java)
```java=
// ContextImpl.java
@Override
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
// 透過 ActivityManager 取得代理類,訪問 AMS#broadcastIntentWithFeature 方法
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
AppOpsManager.OP_NONE, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
```
* 透過 ActivityManager 取得代理類,訪問 [**AMS**](https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/services/core/java/com/android/server/am/ActivityManagerService.java)#**broadcastIntentWithFeature** 方法
```java=
// ActivityManagerService.java
public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
String[] requiredPermissions, String[] excludedPermissions, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
// @ 驗證 intent 是否合法
intent = verifyBroadcastLocked(intent);
// 取得使用者進程、Pid、Uid... 等等
final ProcessRecord callerApp = getRecordForAppLOSP(caller);
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
// @ 分析 broadcastIntentLocked
return broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, excludedPermissions, appOp, bOptions, serialized,
sticky, callingPid, callingUid, callingUid, callingPid, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
}
```
1. **verifyBroadcastLocked**:驗證 Intent 合法性,若 AMS 系統尚未啟動完程卻收到註冊時,判斷是否是 `FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT` (只接受在啟動前,動態註冊的廣播接收者) or `FLAG_RECEIVER_REGISTERED_ONLY` (只接受動態註冊的廣播)
```java=
// ActivityManagerService.java
final Intent verifyBroadcastLocked(Intent intent) {
// 必須要有 FileDescriptors
if (intent != null && intent.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
// 取得 Intent 設定的 Flag
int flags = intent.getFlags();
// mProcessesReady 代表 AMS 是否已經啟動
if (!mProcessesReady) { // 這邊我們預設它已經啟動
// if the caller really truly claims to know what they're doing, go
// ahead and allow the broadcast without launching any receivers
if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
// This will be turned into a FLAG_RECEIVER_REGISTERED_ONLY later on if needed.
} else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
// AMS 尚未啟動,所以無法發送廣播
Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
+ " before boot completion");
throw new IllegalStateException("Cannot broadcast before boot completed");
}
}
... 省略部分,升級時、Shell 模式 ...等等
return intent;
}
```
2. broadcastIntentLocked:這個方法較長只挑重點講,這個函數重點是分析出對使用者發出的這則消息有興趣的 Receiver,並找到相對應的 BroadcastQueue,並呼叫 #**scheduleBroadcastsLocked**
:::success
* broadcastIntentLocked 會整理動態、靜態註冊的接收者,並按照 **優先級高低排序儲存在不同列表中**,再將這兩個列表合併到 receivers (包含了有序、無序廣播)
:::
```java=
// ActivityManagerService.java
final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage,
@Nullable String callerFeatureId, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions,
String[] excludedPermissions, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, /* 省略部分參數 */) {
// 複製一個新 Intent
intent = new Intent(intent);
... 省略部分
// Figure out who all will receive this broadcast.
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
// 並非只發送給已註冊者
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
== 0) {
// 收集 接收者
receivers = collectReceiverComponents(
intent, resolvedType, callingUid, users, broadcastAllowList);
}
... 省略部分
// 有找到對這則消息有興趣的接收者
if ((receivers != null && receivers.size() > 0)
// 依照 intent 取得 BroadcastQueue 列表
BroadcastQueue queue = broadcastQueueForIntent(intent);
// 創建一個 BroadcastRecord 對象
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, appOp, brOptions,
receivers, resultTo, resultCode, resultData, resultExtras,
ordered, sticky, false, userId, allowBackgroundActivityStarts,
backgroundActivityStartsToken, timeoutExempt);
... Debug 訊息
final BroadcastRecord oldRecord =
replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
if (oldRecord != null) {
// Replaced, fire the result-to receiver.
...
} else {
queue.enqueueOrderedBroadcastLocked(r);
// @ 分析 scheduleBroadcastsLocked
queue.scheduleBroadcastsLocked();
}
} else {
... 這個廣播沒有人接收,但仍記錄下來
}
return ActivityManager.BROADCAST_SUCCESS;
}
```
> 
### [BroadcastQueue](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/am/BroadcastQueue.java) - 發送廣播
* 發送廣播需要通過 BroadcastQueue#scheduleBroadcastsLocked 方法:它通過 BroadcastQueue 內部實現的 Handler 來傳送 `BROADCAST_INTENT_MSG` 訊息
```java=
// BroadcastQueue.java
public void scheduleBroadcastsLocked() {
... debug 訊息
if (mBroadcastsScheduled) { // 若已經在發送,則直接返回
return;
}
// 對內部 Handler 發送 BROADCAST_INTENT_MSG 消息
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
```
* BroadcastQueue 內部實現的 Handler (非靜態內部類,可以直接呼叫外部類方法)
```java=
// BroadcastQueue.java
final BroadcastHandler mHandler;
BroadcastQueue(ActivityManagerService service, Handler handler,
String name, BroadcastConstants constants, boolean allowDelayBehindServices) {
mService = service;
mHandler = new BroadcastHandler(handler.getLooper());
... 省略部分
}
private final class BroadcastHandler extends Handler {
public BroadcastHandler(Looper looper) {
super(looper, null, true);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
// 即時訊息
case BROADCAST_INTENT_MSG: {
... 省略部分
processNextBroadcast(true);
} break;
case BROADCAST_TIMEOUT_MSG: {
synchronized (mService) {
broadcastTimeoutLocked(true);
}
} break;
}
}
}
```
* BroadcastQueue#**processNextBroadcast**:
1. 設定 mBroadcastsScheduled 為 false,代表可繼續接收 sendBroadcast
2. 遍歷 BroadcastQueue 內儲存的無序廣播 (`mParallelBroadcasts`),並且每取一個就從列表中移除
:::success
* BroadcastRecord
BroadcastRecord 代表了一個 Broadcast 廣播接收者,並且有附帶了這個廣播接收者有興趣的 BroadcastFilter (多個)
```java=
// 以下是動態註冊,只對 Context.ALARM_SERVICE 有興趣 (當然可以設定多個)
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("Hello", intent.getAction());
}
}, new IntentFilter(Context.ALARM_SERVICE));
```
:::
3. 對 BroadcastRecord 內的每一個 BroadcastFilter,呼叫 deliverToRegisteredReceiverLocked 方法
:::warning
* 若接收者進程正在 backup,就不跳過廣播訊息
:::
```java=
// BroadcastQueue.java
// 已註冊的接收者
final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>();
private void processNextBroadcast(boolean fromMsg) { // 目前接收到是 true
synchronized (mService) {
processNextBroadcastLocked(fromMsg, false);
}
}
// fromMsg: true
// skipOomAdj: false
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
BroadcastRecord r;
...debug 訊息
if (fromMsg) {
mBroadcastsScheduled = false; // 1. 可繼續接收 sendBroadcast
}
// 2. 遍歷內部儲存的無序廣播
while (mParallelBroadcasts.size() > 0) {
// 從第一個開始處理
r = mParallelBroadcasts.remove(0);
... trace 行為
// BroadcastRecord 內有多個 BroadcastFilter
final int N = r.receivers.size(); // 廣播接收者列表
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
... debug 訊息
// @ 3. 分析 deliverToRegisteredReceiverLocked 方法
deliverToRegisteredReceiverLocked(r,
(BroadcastFilter) target, false, i);
}
...
}
}
// ordered: false (目前非有序廣播)
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered, int index) {
...
try {
... debug 訊息
if (filter.receiverList.app != null && filter.receiverList.app.isInFullBackup()) {
// 如果該 Receiver 的進程存在 && 正在 Backup 中,則跳過這則廣播
if (ordered) {
skipReceiverLocked(r);
}
} else {
r.receiverTime = SystemClock.uptimeMillis();
...
// @ 分析 performReceiveLocked
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
...
}
...
} /* 省略 catch */
}
```
* 到 performReceiveLocked 方法後,就是 Receiver 判斷所在的進程是否啟動 (ProcessRecord、其中的 IApplicationThread) 呼叫不同方法
1. Receicer 進程已啟動:呼叫 IApplicationThread#scheduleRegisteredReceiver 方法
2. Receicer 進程未啟動:呼叫 IIntentReceiver#performReceive 方法
```java=
// BroadcastQueue.java
void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, int sendingUser)
throws RemoteException {
if (app != null) {
final IApplicationThread thread = app.getThread();
// 檢查目標進程是否存在
if (thread != null) {
try {
// 呼叫目標 (APP) 進程的 scheduleRegisteredReceiver 方法
thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser,
app.mState.getReportedProcState());
} /* 省略 catch */
} else {
// Application has died. Receiver doesn't exist.
throw new RemoteException("app.thread must not be null");
}
} else {
// 接收者進程尚未啟動
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
}
}
```
> 
### 創建 Receiver 進程
* 若發送給一個尚未啟動的進程,則會透過 **AMS#startProcessLocked** 啟動 Receiver 所屬的進程
```java=
// BroadcastQueue.java
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
BroadcastRecord r;
...省略部分
// Hard case: need to instantiate the receiver, possibly
// starting its application process to host it.
ResolveInfo info = (ResolveInfo)nextReceiver;
ComponentName component = new ComponentName(
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name);
...
String targetProcess = info.activityInfo.processName;
ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
info.activityInfo.applicationInfo.uid);
...
// 若 app 不存在才會走到這一步
r.curApp = mService.startProcessLocked(targetProcess,
info.activityInfo.applicationInfo, true,
r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
new HostingRecord("broadcast", r.curComponent), isActivityCapable
? ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY,
(r.intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false);
if (r.curApp == null) {
// 無法創建 目標進程
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
r.state = BroadcastRecord.IDLE;
return;
}
maybeAddAllowBackgroundActivityStartsToken(r.curApp, r);
// 標明當前有一個等待中的 BroadcastRecord 要處理
mPendingBroadcast = r;
mPendingBroadcastRecvIndex = recIdx;
}
```
## Broadcast 接收
### App 進程已啟動 - 接收廣播
* 前面透過 BroadcastQueue 傳送廣播訊息到指定進程:呼叫方法 **scheduleRegisteredReceiver** 是由 [**ActivityThread**](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/ActivityThread.java)#ApplicationThread 實作
```java=
// ActivityThread.java
public final class ActivityThread extends ClientTransactionHandler
implements ActivityThreadInternal {
private class ApplicationThread extends IApplicationThread.Stub {
... 省略其他方法
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);
// 分析 IIntentReceiver#performReceive
receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
sticky, sendingUser);
}
}
}
```
* IIntentReceiver 是 [**LoadedApk**](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/LoadedApk.java) 的內部類,也就是我們最初在跟 AMS 通訊時打包的 IIntentReceiver.Stub
```java=
// LoadedApk#ReceiverDispatcher.java
static final class ReceiverDispatcher {
final static class InnerReceiver extends IIntentReceiver.Stub {
final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
final LoadedApk.ReceiverDispatcher mStrongRef;
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
final LoadedApk.ReceiverDispatcher rd;
// intent 有可能為 null
if (intent == null) {
Log.wtf(TAG, "Null intent received");
rd = null;
} else {
rd = mDispatcher.get();
}
...debug 訊息
if (rd != null) {
// @ 分析 performReceive
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);
} else {
... 省略部分
IActivityManager mgr = ActivityManager.getService();
try {
if (extras != null) {
extras.setAllowFds(false);
}
// @ 若進程尚未啟動 finishReceiver
mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
// 將要傳輸的資料封裝程 Args 對象
final Args args = new Args(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
...
// 透過 mActivityThread 傳出訊息到主線程 Handler (or 指定 Handler)
// @ 分析 Arg#getRunnable 對象
if (intent == null || !mActivityThread.post(args.getRunnable())) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManager.getService();
... debug 訊息
args.sendFinished(mgr);
}
}
}
}
```
* 創建 Args 類,透過 Args#getRunnable 取得一個 Runnable,將 Runnable 加入使用指定 Handler (預設是 ActivityThread 中的 H 類,也就是主線程)
```java=
// LoadedApk#ReceiverDispatcher#Args.java
// 使用者最初傳入的 Receiver
final BroadcastReceiver mReceiver;
final class Args extends BroadcastReceiver.PendingResult {
public final Runnable getRunnable() {
return () -> {
final BroadcastReceiver receiver = mReceiver;
final boolean ordered = mOrdered;
... 省略部分
try {
...
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
} /* 省略 catch */
if (receiver.getPendingResult() != null) {
finish();
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
};
}
}
```
> 
### App 未啟動 - 不處理下個 BroadcastRecord
* IIntentReceiver 是 [**LoadedApk**](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/LoadedApk.java) 的內部類,也就是我們最初在跟 AMS 通訊時打包的 IIntentReceiver.Stub
* 若 APP 尚未啟動,則無法取得 LoadedApk.ReceiverDispatcher 對象,就會呼叫 [**AMS**](https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/services/core/java/com/android/server/am/ActivityManagerService.java)#**finishReceiver** 方法
```java=
// LoadedApk#ReceiverDispatcher.java
static final class ReceiverDispatcher {
final static class InnerReceiver extends IIntentReceiver.Stub {
final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
final LoadedApk.ReceiverDispatcher mStrongRef;
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
final LoadedApk.ReceiverDispatcher rd;
// intent 有可能為 null
if (intent == null) {
Log.wtf(TAG, "Null intent received");
rd = null;
} else {
rd = mDispatcher.get();
}
...debug 訊息
if (rd != null) {
...
} else {
... 省略部分
IActivityManager mgr = ActivityManager.getService();
try {
if (extras != null) {
extras.setAllowFds(false);
}
// @ 若進程尚未啟動 finishReceiver
mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
```
* 目前的狀況是 App 端的 Receiver 沒有啟動,所以觸發 AMS#finishReceiver 方法,該方法主要做三件事情
1. 將 IBinder 傳入 BroadcastQueue 查看對應的 BroadcastRecord
2. 透過 BroadcastQueue#finishReceiverLocked 查看 是否已經完成發送
3. 若發送完成則處理下一個 BroadcastRecord (目前狀況是沒完成,所以不會處理下一條訊息)
```java=
// ActivityManagerService.java
public void finishReceiver(IBinder who, int resultCode, String resultData,
Bundle resultExtras, boolean resultAbort, int flags) {
... 省略部分
try {
boolean doNext = false;
BroadcastRecord r;
BroadcastQueue queue;
synchronized(this) {
if (isOnOffloadQueue(flags)) {
queue = mOffloadBroadcastQueue;
} else {
queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
? mFgBroadcastQueue : mBgBroadcastQueue;
}
// 1. 將 IBinder 傳入 BroadcastQueue 查看對應的 BroadcastRecord
r = queue.getMatchingOrderedReceiver(who);
if (r != null) {
// 2. 透過 BroadcastQueue#finishReceiverLocked 查看 是否已經完成發送
doNext = r.queue.finishReceiverLocked(r, resultCode,
resultData, resultExtras, resultAbort, true);
}
if (doNext) {
// 3. 若發送完成則處理下一個 BroadcastRecord (目前狀況是沒完成,所以不會處理下一條訊息)
r.queue.processNextBroadcastLocked(/*fromMsg=*/ false, /*skipOomAdj=*/ true);
}
// 調整 Oom_adj 數值
trimApplicationsLocked(false, OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
```
## Appendix & FAQ
:::info
:::
###### tags: `Android Framework`