sendBroadcast流程(二)
阿新 • • 發佈:2018-12-10
上節:sendBroadcat流程(一)中分析了AMS.broadcastIntentLocked中的處理。
接下來分析廣播的派發過程,即分析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; }
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; } } }
接下來看processNextBroadcast函式
第一階段,處理非序列廣播:
final void processNextBroadcast(boolean fromMsg) { synchronized(mService) { BroadcastRecord r; mService.updateCpuStats(); if (fromMsg) { mBroadcastsScheduled = false; } // First, deliver any non-serialized broadcasts right away. 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); 【1.1】 deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i); } addBroadcastToHistoryLocked(r); }
【1.1】deliverToRegisteredReceiverLocked
private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, booleanordered) {
booleanskip = false;
//檢查傳送程序是否有filter要求的許可權
if(filter.requiredPermission != null) {
intperm = checkComponentPermission(filter.requiredPermission,
r.callingPid, r.callingUid, -1, true);
if(perm != PackageManager.PERMISSION_GRANTED) skip = true;
}
//檢查接收者是否有傳送者要求的許可權
if(r.requiredPermission != null) {
intperm = checkComponentPermission(r.requiredPermission,
filter.receiverList.pid, filter.receiverList.uid, -1, true);
if(perm != PackageManager.PERMISSION_GRANTED) skip = true;
}
if(!skip) {
if(ordered) {
......//設定一些狀態,成員變數等資訊,不涉及廣播發送
}
try {
//傳送廣播
performReceiveLocked(filter.receiverList.app,
filter.receiverList.receiver,new Intent(r.intent), r.resultCode,
r.resultData, r.resultExtras, r.ordered, r.initialSticky);
if(ordered) r.state = BroadcastRecord.CALL_DONE_RECEIVE;
}......
}
}
}
再看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) {
//如果app及app.thread不為null,則排程scheduleRegisteredReceiver
// If we have an app thread, do the call through that so it is
// correctly ordered with other one-way calls.
try {
//scheduleRegisteredReceiver僅針對動態receiver
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.repProcState);
// TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
// DeadObjectException when the process isn't actually dead.
//} catch (DeadObjectException ex) {
// Failed to call into the process. It's dying so just let it die and /
//move on.
// throw ex;
} catch (RemoteException ex) {
// Failed to call into the process. It's either dying or wedged. Kill it
//gently.
synchronized (mService) {
Slog.w(TAG, "Can't deliver broadcast to " + app.processName
+ " (pid " + app.pid + "). Crashing it.");
app.scheduleCrash("can't deliver broadcast");
}
throw ex;
}
} else {
// Application has died. Receiver doesn't exist.
throw new RemoteException("app.thread must not be null");
}
} else {
//否則呼叫IIntentReceiver的performReceive函式
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
}
}
對於動態receiver而言,大部分情況下會執行if分支,所以應用程序ApplicationThread的scheduleRegisteredReceiver函式將被呼叫。
scheduleRegisteredReceiver函式
// This function exists to make sure all receiver dispatching is
// correctly ordered, since these are one-way calls and the binder driver
// applies transaction ordering per object for such calls.
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);
}
此處的reciever是registerReceiver時傳入的,實際型別是LoadedApk.ReceiverDispatcher.InnerReceiver,來看它的performReceive函式:
@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 (ActivityThread.DEBUG_BROADCAST) {
int seq = intent.getIntExtra("seq", -1);
}
if (rd != null) {
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);
} else {
// The activity manager dispatched a broadcast to a registered
// receiver in this process, but before it could be delivered the
// receiver was unregistered. Acknowledge the broadcast on its
// behalf so that the system's broadcast sequence can continue.
IActivityManager mgr = ActivityManager.getService();
try {
if (extras != null) {
extras.setAllowFds(false);
}
mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
又呼叫了LoadedApk.ReceiverDispatcher的performReceive函式:
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
final Args args = new Args(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
if (intent == null) {
Log.wtf(TAG, "Null intent received");
}else {
//log 資訊
}
//mActivityThread是一個Handler,SDK中的兩個同名registerReceiver,
//沒有傳遞Handler,則使用主執行緒的Handler
if (intent == null || !mActivityThread.post(args.getRunnable())) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManager.getService();
args.sendFinished(mgr);
}
}
}
scheduleRegisteredReceiver最終向主執行緒的Handler投遞了一個Runnable物件,該Runnable中會在主執行緒中執行:
public final Runnable getRunnable() {
return () -> {
final BroadcastReceiver receiver = mReceiver;
final boolean ordered = mOrdered;
final IActivityManager mgr = ActivityManager.getService();
final Intent intent = mCurIntent;
if (intent == null) {
Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched
+ ": run() previously called at "
+ Log.getStackTraceString(mPreviousRunStacktrace));
}
mCurIntent = null;
mDispatched = true;
mPreviousRunStacktrace = new Throwable("Previous stacktrace");
if (receiver == null || intent == null || mForgotten) {
if (mRegistered && ordered) {
sendFinished(mgr);
}
return;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
//呼叫動態receiver的onReceive函式
receiver.onReceive(mContext, intent);
} catch (Exception e) {
if (mRegistered && ordered) {
sendFinished(mgr);
}
if (mInstrumentation == null ||!mInstrumentation.onException(mReceiver, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException("Error receiving broadcast " + intent
+ " in " + mReceiver, e);
}
}
if (receiver.getPendingResult() != null) {
//呼叫BroadcastReceiver的finish完成工作,通知AMS
finish();
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
};
}
/**
* Finish the broadcast. The current result will be sent and the
* next broadcast will proceed.
*/
public final void finish() {
if (mType == TYPE_COMPONENT) {
final IActivityManager mgr = ActivityManager.getService();
if (QueuedWork.hasPendingWork()) {
// If this is a broadcast component, we need to make sure any
// queued work is complete before telling AM we are done, so
// we don't have our process killed before that. We now know
// there is pending work; put another piece of work at the end
// of the list to finish the broadcast, so we don't block this
// thread (which may be the main thread) to have it finished.
//
// Note that we don't need to use QueuedWork.addFinisher() with the
// runnable, since we know the AM is waiting for us until the
// executor gets to it.
QueuedWork.queue(new Runnable() {
@Override public void run() {
sendFinished(mgr);
}
}, false);
} else {
sendFinished(mgr);
}
} else if (mOrderedHint && mType != TYPE_UNREGISTERED) {
final IActivityManager mgr = ActivityManager.getService();
sendFinished(mgr);
}
}
/** @hide */
public void sendFinished(IActivityManager am) {
synchronized (this) {
if (mFinished) {
throw new IllegalStateException("Broadcast already finished");
}
mFinished = true;
try {
if (mResultExtras != null) {
mResultExtras.setAllowFds(false);
}
if (mOrderedHint) {
am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
mAbortBroadcast, mFlags);
} else {
// This broadcast was sent to a component; it is not ordered,
// but we still need to tell the activity manager we are done.
am.finishReceiver(mToken, 0, null, null, false, mFlags);
}
} catch (RemoteException ex) {
}
}
}
會呼叫到ActivityManagerService的finishReceiver函式:
public void finishReceiver(IBinder who, int resultCode, String resultData,
Bundle resultExtras, boolean resultAbort, int flags) {
// Refuse possible leaked file descriptors
if (resultExtras != null && resultExtras.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Bundle");
}
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) {
//判斷是否需要繼續排程後續的廣播發送
doNext = r.queue.finishReceiverLocked(r, resultCode,
resultData, resultExtras, resultAbort, true);
}
}
if (doNext) {
r.queue.processNextBroadcast(false);
}
trimApplications();
} finally {
Binder.restoreCallingIdentity(origId);
}
}
processNextBroadcast第二階段,處理序列廣播:
final void processNextBroadcast(boolean fromMsg) {
synchronized(mService) {
BroadcastRecord r;
...//第一階段處理序列廣播
//第二階段
// Now take care of the next serialized one...
// If we are waiting for a process to come up to handle the next
// broadcast, then do nothing at this point. Just in case, we
// check that the process we're waiting for still exists.
/*
接下來處理mOrderedBroadcasts中的成員,如果接收者所在的程序還未啟動,則需等待。
mPendingBrodcast用於標識因為應用程序還未啟動而處於等待狀態的BrodcastRecord。
*/
if (mPendingBroadcast != null) {
boolean isDead;
synchronized (mService.mPidsSelfLocked) {
ProcessRecord proc =
mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);
isDead = proc == null || proc.crashing;
}
/*重要說明
判斷要等待的程序是否為dead程序,如果沒有dead程序,則繼續等待。仔細思考,此處直接
返回會有什麼問題。
問題不小!假設有兩個ordered廣播A和B,有兩個接收者,AR和BR,並且BR所
在程序已經啟動並完成初始化Android執行環境。如果processNextBroadcast先處理A,
再處理B,那麼此處B的處理將因為mPendingBroadcast不為空而被延後。雖然B和A
之間沒有任何關係(例如完全是兩個不同的廣播訊息),
但是事實上,大多數開發人員理解的order是針對單個廣播的,例如A有5個接收者,那麼對這
5個接收者的廣播的處理是序列的。通過此處的程式碼發現,系統竟然序列處理A和B廣播,即
B廣播要待到A的5個接收者都處理完了才能處理。
*/
if (!isDead) {
// It's still alive, so keep waiting
return;
} else {
mPendingBroadcast.state = BroadcastRecord.IDLE;
mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
mPendingBroadcast = null;
}
}
boolean looped = false;
do {
//mOrderedBroadcasts處理完畢
if (mOrderedBroadcasts.size() == 0) {
// No more broadcasts pending, so all done!
mService.scheduleAppGcsLocked();
if (looped) {
// If we had finished the last ordered broadcast, then
// make sure all processes have correct oom and sched
// adjustments.
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();
///如果總耗時超過2倍的接收者個數*每個接收者最長處理時間(10秒),則
//強制結束這條廣播的處理
if ((numReceivers > 0) &&
(now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
broadcastTimeoutLocked(false); // forcibly finish this broadcast
forceReceive = true;
r.state = BroadcastRecord.IDLE;
}
}
if (r.state != BroadcastRecord.IDLE) {
return;
}
//如果下面這個if條件滿足,則表示該條廣播要麼已經全部被處理,要麼被中途取消
if (r.receivers == null || r.nextReceiver >= numReceivers
|| r.resultAbort || forceReceive) { //沒有接收此廣播的receiver了
if (r.resultTo != null) {
try {
//將該廣播的處理結果傳給設定了resultTo的接收者
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent), r.resutCode,
r.resultData, r.resultExtras, false, false, r.userId);
catch (RemoteException e) {
r.resultTo = null;
}
}
cancelBroadcastTimeoutLocked();
addBroadcastToHistoryLocked(r);
if (r.intent.getComponent() == null && r.intent.getPackage() == null
&& (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
// This was an implicit broadcast... let's record it for posterity.
mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
}
mOrderedBroadcasts.remove(0);
r = null;
looped = true;
continue;
} while (r == null);
....
} //end of synchronized(mService)
}
第二階段的工作總結:
- 首先根據是否處於pending狀態進行相關操作
- 處理超時的廣播記錄。超時時間是2*BROADCAST_TIMEOUT*numReceivers,BROADCAST_TIMEOUT預設為10秒。由於涉及到建立程序,初始化Android執行環境等操作,所以此處的超時時間還乘以一個固定倍數2。
第三階段
// Get the next receiver...
int recIdx = r.nextReceiver++;
// Keep track of when this receiver started, and make sure there
// is a timeout message pending to kill it if need be.
r.receiverTime = SystemClock.uptimeMillis();
if (recIdx == 0) {
r.dispatchTime = r.receiverTime;//記錄本廣播第一次處理開始的時間
r.dispatchClockTime = System.currentTimeMillis();
}
//設定廣播處理超時時間,BROADCAST_TIMEOUT為10秒
if (!mPendingBroadcastTimeoutMessage) {
long timeoutTime = r.receiverTime + mTimeoutPeriod;
setBroadcastTimeoutLocked(timeoutTime);
}
final BroadcastOptions brOptions = r.options;
//取該條廣播的下一個接收者
final Object nextReceiver = r.receivers.get(recIdx);
if (nextReceiver instanceof BroadcastFilter) {
// Simple case: this is a registered receiver who gets
// a direct call.
//如果是動態接收者,則直接呼叫deliverToRegisteredReceiverLocked處理
BroadcastFilter filter = (BroadcastFilter)nextReceiver;
deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
if (r.receiver == null || !r.ordered) {
// The receiver has already finished, so schedule to
// process the next one.
r.state = BroadcastRecord.IDLE;
scheduleBroadcastsLocked();
} else {
if (brOptions!=null&&brOptions.getTemporaryAppWhitelistDuration()> 0) {
scheduleTempWhitelistLocked(filter.owningUid,
brOptions.getTemporaryAppWhitelistDuration(), r);
}
}
return;//已經通知一個接收者去處理該廣播,需要等它的處理結果,所以此處直接返回
}
// 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);
......//檢測是否為skip的package
String targetProcess = info.activityInfo.processName;
ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
info.activityInfo.applicationInfo.uid, false);
.....
r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
r.state = BroadcastRecord.APP_RECEIVE;
r.curComponent = component;
r.curReceiver = info.activityInfo;
.....//正在處理廣播,package不能被stop
// Is this receiver's application already running?
//如果接收者所在的程序已經啟動
if (app != null && app.thread != null && !app.killed) {
try {
app.addPackage(info.activityInfo.packageName,
info.activityInfo.applicationInfo.versionCode,
mService.mProcessStats);
processCurBroadcastLocked(r, app);
return;//已經觸發接收者處理本廣播,需要等待處理結果
} catch (RemoteException e) {
} catch (RuntimeException e) {
Slog.wtf(TAG, "Failed sending broadcast to "
+ r.curComponent + " with " + r.intent, e);
// If some unexpected exception happened, just skip
// this broadcast. At this point we are not in the call
// from a client, so throwing an exception out from here
// will crash the entire system instead of just whoever
// sent the broadcast.
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
// We need to reset the state if we failed to start the receiver.
r.state = BroadcastRecord.IDLE;
return;
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
// Not running -- get it started, to be executed when the app comes up.
//如果程序沒啟動,則要先啟動程序
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) {
//程序啟動失敗的處理
// Ah, this recipient is unavailable. Finish it if necessary,
// and mark the broadcast record as ready for the next.
Slog.w(TAG, "Unable to launch app "
+ info.activityInfo.applicationInfo.packageName + "/"
+ info.activityInfo.applicationInfo.uid + " for broadcast "
+ r.intent + ": process is bad");
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
r.state = BroadcastRecord.IDLE;
return;
}
mPendingBroadcast = r; //設定mPendingBroadcast
mPendingBroadcastRecvIndex = recIdx;
第三階段的處理總結:
- 如果廣播接收者為動態註冊物件,則直接呼叫deliverToRegisteredReceiverLocked處理它;
- 如果廣播接收者為靜態註冊物件,並且該物件對應的程序已經存在,則呼叫processCurBroadcastLocked處理它;
- 如果廣播接收者為靜態註冊物件,並且該物件對應的程序還不存在,則需要建立該程序,這是最糟糕的情況。
sendBroadcast流程圖: