Android Broadcast廣播機制分析
基於Android 6.0的原始碼剖析, 分析android廣播的傳送與接收流程。
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服務端物件caller
和receiver
,都代表執行註冊廣播動作所在的程序. 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 廣播註冊小結
註冊廣播:
- 傳遞的引數為廣播接收者BroadcastReceiver和Intent過濾條件IntentFilter;
- 建立物件LoadedApk.ReceiverDispatcher.InnerReceiver,該物件繼承於IIntentReceiver.Stub;
- 通過AMS把當前程序的ApplicationThread和InnerReceiver物件的代理類,註冊登記到system_server程序;
- 當廣播receiver沒有註冊過,則建立廣播接收者佇列ReceiverList,該物件繼承於ArrayList, 並新增到AMS.mRegisteredReceivers(已註冊廣播佇列);
- 建立BroadcastFilter,並新增到AMS.mReceiverResolver;
- 將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 小結
傳送廣播過程:
- 預設不傳送給已停止(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES)的應用包;
- 處理各種PACKAGE,TIMEZONE等相關的系統廣播;
- 當為粘性廣播,則將sticky廣播增加到list,並放入mStickyBroadcasts裡面;
- 當廣播的Intent沒有設定FLAG_RECEIVER_REGISTERED_ONLY,則允許靜態廣播接收者來處理該廣播; 建立BroadcastRecord物件,並將該物件加入到相應的廣播佇列, 然後呼叫BroadcastQueue的
scheduleBroadcastsLocked
()方法來完成的不同廣播處理:
處理方式:
- Sticky廣播: 廣播註冊過程處理AMS.registerReceiver,開始處理粘性廣播,見小節[2.5];
- 建立BroadcastRecord物件;
- 並新增到mParallelBroadcasts佇列;
- 然後執行queue.scheduleBroadcastsLocked;
- 並行廣播: 廣播發送過程處理,見小節[3.4.6]
- 只有動態註冊的mRegisteredReceivers才會並行處理;
- 會建立BroadcastRecord物件;
- 並新增到mParallelBroadcasts佇列;
- 然後執行queue.scheduleBroadcastsLocked;
- 序列廣播: 廣播發送廣播處理,見小節[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]