源碼基于Android 11 API 30
BroadcastReceiver是一種消息型組件,用于在不同的組件或者是不同的應用之間傳遞信息。同樣的BroadcastReceiver也不能被用戶感知,BroadcastReceiver也叫廣播,廣播的注冊有兩種方式:靜態注冊和動態注冊。靜態注冊是指在AndroidManifest中注冊廣播,這種廣播在應用安裝時會被系統解析,此種形式的廣播不需要應用啟動就可以收到相應的廣播。動態注冊廣播需要通過Context.registerReceiver()來實現,并且在不需要的時候要通過Context.unRegisterReceiver()來解除廣播,此種形態的廣播必須要應用啟動才能注冊并接收廣播,因為應用不啟動就無法注冊廣播,無法注冊廣播就無法收到相應的廣播。在實際開發中通過Context的一系列send方法來發送廣播,被發送的廣播會被系統發送給感興趣的廣播接收者,發送和接收過程的匹配是通過廣播接收者的<intent-filter>來描述的。可以發現,BroadcastReceiver組件可以用來實現低耦合的觀察者模式,觀察者和被觀察者之間可以沒有任何耦合。由于BroadcastReceiver的特性,它不適合用來執行耗時操作。BroadcastReceiver組件一般來說不需要停止,它也沒有停止的概念。
下面從廣播的注冊、發送與接收幾個過程展開介紹。
1. 廣播的注冊
廣播的注冊分為動態注冊與靜態注冊兩種。靜態注冊的注冊過程是在應用安裝時由PackageManager-Service完成注冊的。我們這里主要介紹動態注冊的過程。下面是一個典型的動態注冊、發送于接受廣播的代碼:
...
//通常需要自定義一個BroadcastReceiver,這里只是示例避免代碼過長
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//Do something
abortBroadcast();
}
};
IntentFilter intentFilter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_broadcast);
intentFilter = new IntentFilter();
intentFilter.addAction("com.example.myapplication.DEMOBROADCAST");
registerReceiver(broadcastReceiver,intentFilter);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.myapplication.DEMOBROADCAST");
sendBroadcast(intent);
}
});
}
...
上面的代碼可以明顯的看到,廣播的著冊方法是registerReceiver,這個方法是在ContextWrapper中定義的,與Service的啟動與綁定類似,registerReceiver方法有調用了mBase的方法,mBase的實現是ContextImpl,ContextImpl的registerReceiver方法在嵌套調用后最后調用了registerReceiverInternal方法,具體看下代碼:
//ContextWrapper.java
...
@Override
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter) {
return mBase.registerReceiver(receiver, filter);
}
...
//ContextImpl.java
...
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
IIntentReceiver rd = null;
if (receiver != null) {//判斷receiver是否存在
//判斷mPackageInfo(LoadedApk類型)與Context是否都存在
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
//獲取IIntentReceiver
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
//mPackageInfo不存在
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
//創建IIntentReceiver
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
try {
//獲取AMS調用registerReceiverWithFeature方法
final Intent intent = ActivityManager.getService().registerReceiverWithFeature(
mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(), rd,
filter, broadcastPermission, userId, flags);
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
intent.prepareToEnterProcess();
}
return intent;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
...
最后可以看到調用了AMS的registerReceiverWithFeature,上面代碼中有一個重要變量rd,IIntentReceiver類型,這顯然是一個Binder接口,具體實現在LoadedApk.ReceiverDispatcher.InnerReceiver:
static final class ReceiverDispatcher {
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;
}
...
}
回到AMS的registerReceiverWithFeature方法,方法比較長,核心處理添加了注釋:
public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
String callerFeatureId, IIntentReceiver receiver, IntentFilter filter,
String permission, int userId, int flags) {
enforceNotIsolatedCaller("registerReceiver");
ArrayList<Intent> stickyIntents = null;
ProcessRecord callerApp = null;
final boolean visibleToInstantApps
= (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
int callingUid;
int callingPid;
boolean instantApp;
synchronized(this) {
if (caller != null) {
//獲取ProcessRecord,其用于描述注冊的接收者Activity所在應用程序進程
callerApp = getRecordForAppLocked(caller);
...
callingUid = callerApp.info.uid;
callingPid = callerApp.pid;
} else {
callerPackage = null;
callingUid = Binder.getCallingUid();
callingPid = Binder.getCallingPid();
}
...
//根據傳入的IntentFilter獲取Action列表
Iterator<String> actions = filter.actionsIterator();
if (actions == null) {
ArrayList<String> noAction = new ArrayList<String>(1);
noAction.add(null);
actions = noAction.iterator();
}
// userIds表示應用程序的uid,對于Android系統來說,用戶就是一個個的應用程序。
int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
while (actions.hasNext()) {
String action = actions.next();
for (int id : userIds) {
//根據Action列表與應用程序列表(userIds)獲取所有粘性廣播(StickyBroadcast)
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
if (stickies != null) {
//獲取所有粘性廣播的intent
ArrayList<Intent> intents = stickies.get(action);
if (intents != null) {
if (stickyIntents == null) {
stickyIntents = new ArrayList<Intent>();
}
//保存粘性廣播的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);
// Don't provided intents that aren't available to instant apps.
if (instantApp &&
(intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
continue;
}
...
}
}
...
synchronized (this) {
...
//獲取ReceiverList
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
//ReceiverList為空新建
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("Too many receivers, total of "
+ totalReceiversForApp + ", registered for pid: "
+ rl.pid + ", callerPackage: " + callerPackage);
}
rl.app.receivers.add(rl);
} else {
...
}
}
//創建BroadcastFilter用來記錄已注冊的廣播接收者信息
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
permission, callingUid, userId, instantApp, visibleToInstantApps);
//判斷接收者列表ReceiverList中是否存在對應接收者,不存在則添加
if (rl.containsFilter(filter)) {
Slog.w(TAG, "Receiver with filter " + filter
+ " already registered for pid " + rl.pid
+ ", callerPackage is " + callerPackage);
} else {
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadcast");
}
//記錄接收者,AMS全局變量,
//當AMS接收到廣播時會從mReceiverResolver找到所有的接收者,實現注冊的效果。
mReceiverResolver.addFilter(bf);
}
// 廣播隊列中入隊所有將符合filter的粘性廣播
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);
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, null, -1, -1, false, null, null, OP_NONE, null, receivers,
null, 0, null, null, false, true, true, -1, false,
false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
}
return sticky;
}
}
以上就是廣播注冊的過程,具體的步驟在注釋中一有所體現。
2. 廣播的發送與接收
2.1 ContextImp 調用AMS
我們知道廣播有標準廣播(無序廣播)、有序廣播和粘性廣播。下面還是以開始那個例子(標準廣播)展開介紹。與廣播的注冊類似,首先是調用了ContextWraper的sendBroadcast:
...
@Override
public void sendBroadcast(Intent intent) {
mBase.sendBroadcast(intent);
}
...
sendBroadcast調用了ContextImp的sendBroadcast方法:
...
@Override
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
...
上面的代碼,很明顯調用了AMS的broadcastIntentWithFeature方法:
public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
String[] requiredPermissions, int appOp, Bundle bOptions,
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();
try {
return broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, appOp, bOptions, serialized, sticky,
callingPid, callingUid, callingUid, callingPid, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
}
最后調用了AMS的broadcastIntentLocked方法,方法特別的長,這里這給出部分源碼:
final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage,
@Nullable String callerFeatureId, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
int realCallingPid, int userId, boolean allowBackgroundActivityStarts,
@Nullable int[] broadcastWhitelist) {
...
//獲取注冊的粘性廣播
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
if (stickies == null) {
stickies = new ArrayMap<>();
mStickyBroadcasts.put(userId, stickies);
}
//找到符合當前Action的廣播
ArrayList<Intent> list = stickies.get(intent.getAction());
if (list == null) {
list = new ArrayList<>();
stickies.put(intent.getAction(), list);
}
...
//接收者存在
if ((receivers != null && receivers.size() > 0)
|| resultTo != null) {
//獲取廣播隊列,獲取BroadcastRecord信息
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
resultData, resultExtras, ordered, sticky, false, userId,
allowBackgroundActivityStarts, timeoutExempt);
...
queue.enqueueOrderedBroadcastLocked(r);
//執行廣播schedule
queue.scheduleBroadcastsLocked();
}
...
return ActivityManager.BROADCAST_SUCCESS;
}
從上面的代碼可以看出,最后AMS調用了BroadcastQueue的scheduleBroadcastsLocked方法。
2.2 ContextImp 調用AMS調用BroadcastReceiver
接上一節的代碼繼續看,BroadcastQueue的scheduleBroadcastsLocked方法:
public void scheduleBroadcastsLocked() {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
+ mQueueName + "]: current="
+ mBroadcastsScheduled);
if (mBroadcastsScheduled) {
return;
}
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
scheduleBroadcastsLocked方法內部,通過BroadcastHandler發送了一個消息:BROADCAST_INTENT_MSG,這肯定交由對應的handleMessage方法處理,我們再看下BroadcastHandler的handleMessage方法:
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_INTENT_MSG: {
if (DEBUG_BROADCAST) Slog.v(
TAG_BROADCAST, "Received BROADCAST_INTENT_MSG ["
+ mQueueName + "]");
processNextBroadcast(true);
} break;
case BROADCAST_TIMEOUT_MSG: {
synchronized (mService) {
broadcastTimeoutLocked(true);
}
} break;
}
}
上面代碼很明顯,處理BROADCAST_INTENT_MSG類型消息后,調用了processNextBroadcast方法,然后又調用了processNextBroadcastLocked方法,方法比較長,特殊處理也很多,這里只關注下標準廣播的處理:
final void processNextBroadcast(boolean fromMsg) {
synchronized (mService) {
processNextBroadcastLocked(fromMsg, false);
}
}
...
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
...
if (fromMsg) {//已經處理了BROADCAST_INTENT_MSG類型的消息
mBroadcastsScheduled = false;
}
// 處理無序廣播,也就是標準的廣播
while (mParallelBroadcasts.size() > 0) {
//獲取廣播
r = mParallelBroadcasts.remove(0);
...
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Delivering non-ordered on [" + mQueueName + "] to registered "
+ target + ": " + r);
//廣播發送給相應的接收者
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
}
addBroadcastToHistoryLocked(r);
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
+ mQueueName + "] " + r);
}
...
}
下面繼續看下deliverToRegisteredReceiverLocked方法:
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered, int index) {
....//省略一堆驗證
// 有序廣播的處理.
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.curReceivers.add(r);
mService.updateOomAdjLocked(r.curApp, true,
OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
}
}
try {
if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
"Delivering to " + filter + " : " + r);
if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
//如果是有序廣播,繼續傳給下一個接收者.
if (ordered) {
skipReceiverLocked(r);
}
} else {
r.receiverTime = SystemClock.uptimeMillis();
maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
//各種檢查及驗證后最終調用的方法
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
if (r.allowBackgroundActivityStarts && !r.ordered) {
postActivityStartTokenRemoval(filter.receiverList.app, r);
}
}
if (ordered) {
r.state = BroadcastRecord.CALL_DONE_RECEIVE;
}
} catch (RemoteException e) {
...
}
}
繼續看performReceiveLocked方法:
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) {//驗證應用程序進程是否已運行
// If we have an app thread, do the call through that so it is
// 應用程序進程存在,執行一個單向請求
try {
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.getReportedProcState());
} catch (RemoteException ex) {
...
}
} else {
throw new RemoteException("app.thread must not be null");
}
} else {
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
}
}
上面的應用程序進程app自然是ApplicationThread,繼續看其方法scheduleRegisteredReceiver:
//這個方法是為了保證所有接收者的分發是正確有序的
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);
receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
sticky, sendingUser);
}
上面代碼很簡潔,調用了IIntentReceiver的performReceive方法,IIntentReceiver是通過LoadedApk中的InnerReceiver實現的:
final static class InnerReceiver extends IIntentReceiver.Stub {
...
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
final LoadedApk.ReceiverDispatcher rd;
if (intent == null) {
Log.wtf(TAG, "Null intent received");
rd = null;
} else {
rd = mDispatcher.get();
}
...
if (rd != null) {
//ReceiverDispatcher的調用
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);
} else {
...
}
}
...
}
上面的IIntentReceiver通過AIDL實現進程間通信,最后調用了ReceiverDispatcher的performReceive方法:
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
//封裝廣播的intent信息
final Args args = new Args(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
if (intent == null) {
Log.wtf(TAG, "Null intent received");
} else {
...
}
if (intent == null || !mActivityThread.post(args.getRunnable())) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManager.getService();
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing sync broadcast to " + mReceiver);
args.sendFinished(mgr);
}
}
}
mActivityThread.post(args.getRunnable())的mActivityThread是個Handler,具體實現是H類,這里將args.getRunnable()作為參數傳入Handler的post方法,看下Args的getRunnable方法:
public final Runnable getRunnable() {
return () -> {
final BroadcastReceiver receiver = mReceiver;
final boolean ordered = mOrdered;
...
//獲取AMS
final IActivityManager mgr = ActivityManager.getService();
final Intent intent = mCurIntent;
...
try {
//創建BroadcastReceiver
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
//調用onReceive方法
receiver.onReceive(mContext, intent);
} catch (Exception e) {
...
}
...
};
}
}
代碼最后創建了一個BroadcastReceiver并調用了onReceive方法。