概述
我們從三個方面來分析廣播的流程
- 廣播的註冊
- 廣播的發送
- 廣播的處理
廣播的註冊
廣播的註冊分爲靜態註冊和動態註冊,我們主要分析動態註冊
首先我們從context.registerReceiver()
這個方法開始,看他內部調用了ContextWrapper#registerReceiver
方法
ContextWrapper.java
@Override
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter) {
return mBase.registerReceiver(receiver, filter);
}
mBase的實現類是ContextImpl
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());
}
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();
}
//註釋1
//獲取IIntentReceiver對象
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 {
//註釋2
//調用AMP.registerReceiver
return ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
} catch (RemoteException e) {
return null;
}
}
我們先看一下註釋1
,他的主要作用是獲取IIntentReceiver
對象,其中mPackageInfo
是LoadedApk
類型,我們看一下IIntentReceiver
到底是什麼
LoadedApk.java
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;
}
IIntentReceiver
原來是一個Binder接口
,用於廣播的跨進程通信,他在LoadedApk.ReceiverDispatcher.InnerReceiver
中實現
ActivityManagerService.java
接下來我們看一下註釋2
,ActivityManagerNative.getDefault().registerReceiver
,其中ActivityManagerNative.getDefault()
這個最終會指向ActivityManagerService
,這也是一個Binder用於進程間的通信,我們看一下registerReceiver
這個方法做了什麼
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
int flags) {
...
ProcessRecord callerApp = null;
...
synchronized(this) {
if (caller != null) {
//註釋1
//查詢調用者的進程信息
callerApp = getRecordForAppLocked(caller);
...
//獲取IntentFilter中的actions,這個就是平時所加的action
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) };
while (actions.hasNext()) {
String action = actions.next();
for (int id : userIds) {
//從mStickyBroadcasts中查看用戶的sticky Inten
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
//把粘性廣播添加到列表中
stickyIntents.addAll(intents);
}
}
}
}
}
...
synchronized (this) {
if (callerApp != null && (callerApp.thread == null
|| callerApp.thread.asBinder() != caller.asBinder())) {
// Original caller already died
return null;
}
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
//對於未註冊的廣播,則創建接受者隊列
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
if (rl.app != null) {
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 {
try {
receiver.asBinder().linkToDeath(rl, 0);
} catch (RemoteException e) {
return sticky;
}
rl.linkedToDeath = true;
}
//新建的接受者隊列,添加到已註冊廣播隊列
mRegisteredReceivers.put(receiver.asBinder(), rl);
}
...
//創建BroadcastFilter,並添加到接受者隊列
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId, instantApp, visibleToInstantApps);
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");
}
//新建的BroadcastFilter,添加到mReceiverResolver隊列中
mReceiverResolver.addFilter(bf);
}
...
return sticky;
}
}
這個方法有點長,其中mRegisteredReceivers
記錄着所有已經註冊的廣播
註冊廣播小結
- 傳遞的參數是
BroadcastReceiver
和IntentFilter
- 創建
LoadedApk.ReceiverDispatcher.InnerReceiver
,該對象是一個Binder
- 通過
AMS
把InnerReceiver
對象的代理類,註冊到system_server
進程 - 如果廣播沒有被註冊過,則創建廣播接受者隊列
ReceiverList
,並添加到AMS.mRegisteredReceivers
(已註冊廣播隊列); - 創建
BroadcastFilter
,並添加到AMS.mReceiverResolver
和ReceiverList
發送廣播
發送廣播是調用sendBroadcast()
,其實真正乾貨的是ContextImpl類,廣播分很多種,有序廣播和無序廣播,粘性廣播,這裏我們只分析無序掛廣播
ContextImpl.java
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess();
// 調用AMP.broadcastIntent
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
} catch (RemoteException e) {
...
}
}
還是很熟悉的代碼,最終還是會調用到ActivityManagerService#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 bOptions,
boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
//驗證廣播是否合法
intent = verifyBroadcastLocked(intent);
//獲取調用者進程記錄對象
final ProcessRecord callerApp = getRecordForAppLocked(caller);
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
//註釋1
int res = broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, appOp, bOptions, serialized, sticky,
callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
註釋1處,調用了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) {
...
if ((receivers != null && receivers.size() > 0)
|| resultTo != null) {
//根據intent的flag來判斷前臺隊列或者後臺隊列
BroadcastQueue queue = broadcastQueueForIntent(intent);
//註釋1
//創建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);
//註釋2
//處理廣播
queue.scheduleBroadcastsLocked();
}
}
return ActivityManager.BROADCAST_SUCCESS;
}
這個方法很長,前面省略了很多,前面的工作主要是,把靜態註冊和動態註冊的廣播,按照優先級不同存儲在不同的列表中,然後把倆個列表合併到recevers
列表中,這樣recevers
列表就包含了所有的廣播接收者,然後再註釋1處創建BroadcastRecord
對象並把recevers
傳入,然後再註釋2處調用BroadcastQueue
的scheduleBroadcastsLocked
方法處理廣播
處理廣播
不管哪種廣播最終都會調用scheduleBroadcastsLocked
方法來處理廣播
BroadcastQueue.java
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;
}
此處的Handler
是BroadcastHandler
,消息在BroadcastHandler
中處理
BroadcastHandler.java
private final class BroadcastHandler extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_INTENT_MSG: {
processNextBroadcast(true);
} break;
...
}
}
調用了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
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
}
addBroadcastToHistoryLocked(r);//將廣播添加歷史統計
}
...
}
通過deliverToRegisteredReceiverLocked
方法,把廣播分發給對應的廣播接收者
private void deliverToRegisteredReceiverLocked(BroadcastRecord r, BroadcastFilter filter, boolean ordered) {
...
//檢查發送者是否有BroadcastFilter所需權限
//以及接收者是否有發送者所需的權限等等
//當權限不滿足要求,則skip=true。
...
// 處理廣播
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;
}
...
}
}
這個方法主要是檢查權限,如果權限通過就調用performReceiveLocked
處理廣播
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類對應的方法
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);
}
}
這個方法表示,如果廣播接受者的進程還存在,則通過Binder發送廣播,這裏的app.thread
指的是ApplicationThread
,我們看一下scheduleRegisteredReceiver
這個方法
ActivityThread.java
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.ReceiverDispatcher.InnerReceive
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) {
rd.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser);
} else {
...
}
}
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
//註釋1
final Args args = new Args(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
if (intent == null) {
Log.wtf(TAG, "Null intent received");
} else {
if (ActivityThread.DEBUG_BROADCAST) {
int seq = intent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()
+ " seq=" + seq + " to " + mReceiver);
}
}
if (intent == null || !mActivityThread.post(args.getRunnable())) {//註釋2
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManager.getService();
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing sync broadcast to " + mReceiver);
args.sendFinished(mgr);
}
}
}
註釋1處把廣播的intent對象封裝爲Args,註釋2處利用mActivityThread的post傳入了Arg對象,mActivityThread是一個Handler指向內部類H,註釋2處的args.getRunnable(),就是要處理的邏輯,我們看下這個getRunnable
public final Runnable getRunnable() {
return () -> {
...
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
//註釋1
receiver.onReceive(mContext, intent);
再註釋1處,調用了onReceive方法,這樣註冊的廣播接受者,就收到了消息
參考:http://gityuan.com/2016/06/04/broadcast-receiver/
Android 進階解密