Broadcast发送流程分析
Posted 胖虎
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Broadcast发送流程分析相关的知识,希望对你有一定的参考价值。
android Source Tools : androidxref.com
Original stack trace:
android.app.RemoteServiceException : can’t deliver broadcast
at android.app.ActivityThread
H
.
h
a
n
d
l
e
M
e
s
s
a
g
e
(
A
c
t
i
v
i
t
y
T
h
r
e
a
d
.
j
a
v
a
:
2038
)
a
t
a
n
d
r
o
i
d
.
o
s
.
H
a
n
d
l
e
r
.
d
i
s
p
a
t
c
h
M
e
s
s
a
g
e
(
H
a
n
d
l
e
r
.
j
a
v
a
:
107
)
a
t
a
n
d
r
o
i
d
.
o
s
.
L
o
o
p
e
r
.
l
o
o
p
(
L
o
o
p
e
r
.
j
a
v
a
:
214
)
a
t
a
n
d
r
o
i
d
.
a
p
p
.
A
c
t
i
v
i
t
y
T
h
r
e
a
d
.
m
a
i
n
(
A
c
t
i
v
i
t
y
T
h
r
e
a
d
.
j
a
v
a
:
7682
)
a
t
j
a
v
a
.
l
a
n
g
.
r
e
f
l
e
c
t
.
M
e
t
h
o
d
.
i
n
v
o
k
e
(
M
e
t
h
o
d
.
j
a
v
a
)
a
t
c
o
m
.
a
n
d
r
o
i
d
.
i
n
t
e
r
n
a
l
.
o
s
.
R
u
n
t
i
m
e
I
n
i
t
H.handleMessage(ActivityThread.java:2038) at android.os.Handler.dispatchMessage(Handler.java:107) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7682) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.RuntimeInit
H.handleMessage(ActivityThread.java:2038)atandroid.os.Handler.dispatchMessage(Handler.java:107)atandroid.os.Looper.loop(Looper.java:214)atandroid.app.ActivityThread.main(ActivityThread.java:7682)atjava.lang.reflect.Method.invoke(Method.java)atcom.android.internal.os.RuntimeInitMethodAndArgsCaller.run(RuntimeInit.java:516)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
conclusion: By the above Log information and the following process analysis, we can only conclude that when Step7 was about to distribute the broadcast to the registered BroadcastReceiver, the remote Binder was found dead, but we don’t know why
eg. Android SDK 29 source code for analysis
First. We have found the problem log occurs in the android system code
com.android.server.am.BroadcastQueue.java Line 600
“app.scheduleCrash(“can’t deliver broadcast”);” in the method “performReceiveLocked”
I Found Google developers offering this code comments here (“Failed to call into the process. It’s either dying or wedged. Kill It gently”)
In order to understand their approach, I analyzed the transmission process of Broadcast. The process analysis is as follows
Step1. Context.sendBroadcast(Intent) [can other app] -> in fact is ContextImpl.sendBroadcast(Intent)
function body contracted version
…
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntent(…)
…
This operation will leave current app process, calling AMS is broadcast
Step2. ActivityManagerService.broadcastIntent(…) -> code final call method “ActivityManagerService.broadcastIntentLocked”
function body contracted version
…
// Figure out who all will receive this broadcast.
List receivers = null;
List registeredReceivers = null;
// Need to resolve the intent to interested receivers…
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false /defaultOnly/, userId);
…
…
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(…);
queue.enqueueOrderedBroadcastLocked®;
queue.scheduleBroadcastsLocked();
…
This operation will find the receivers of the broadcast
Get the foreground or background queues from AMS
Construct a BroadcastRecord class object and put it in a BroadcastQueue(This is our focus class, due to this bug that appears here)
Step3. BroadcastQueue.scheduleBroadcastsLocked()
function body contracted version
// Set when we current have a BROADCAST_INTENT_MSG in flight.
if (mBroadcastsScheduled)
return;
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
We can see that this is just to activate the handler if it’s not already activated, because the broadcast we are sending is already waiting in the queue
Step4. BroadcastQueue.BroadcastHandler#handleMessage()
function body contracted version
…
switch (msg.what)
case BROADCAST_INTENT_MSG:
processNextBroadcast(true);
break;
case BROADCAST_TIMEOUT_MSG:
synchronized (mService)
broadcastTimeoutLocked(true);
break;
…
From the code we can clearly see that the final call to processNextBroadcast() method
Step5. BroadcastQueue#processNextBroadcast() -> final call to processNextBroadcastLocked()
function body contracted version
// 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);
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
addBroadcastToHistoryLocked®;
…
We see the real distribution of the broadcast
Step6. BroadcastQueue#deliverToRegisteredReceiverLocked()
function body contracted version
…
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
…
Send this broadcast
Step7. BroadcastQueue#performReceiveLocked()[★★★bug happend method body★★★]
function body compelete verion
//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
// correctly ordered with other one-way calls.
try
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.getReportedProcState());
// 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”);
This bug is happend here, we will go to next method
Step8. ActivityThread#scheduleRegisteredReceiver(IIntentReceiver receiver,…)
function body compelete verion
updateProcessState(processState, false);
receiver.performReceive(…);
receiver is IIntentReceiver impl
Step9. LoadedApk.ReceiverDispatcher.InnerReceiver#performReceive()
function body compelete verion
if (rd != null)
// Rc. rd -> class LoadedApk.ReceiverDispatcher object
rd.performReceive(…);
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.
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
“Finishing broadcast to unregistered receiver”);
IActivityManager mgr = ActivityManager.getService();
try
mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
catch (RemoteException e)
throw e.rethrowFromSystemServer(); // Rc. We need to think about this place
Normally we want rd to be valid
Step10. LoadedApk.ReceiverDispatcher#performReceive()
function body contracted version
…
final Args args = new Args(intent, resultCode, data, extras, ordered, sticky, sendingUser);
…
mActivityThread.post(args.getRunnable())
…
Step11. LoadedApk.Args#getRunnable()
function body contracted version
…
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
…
Done send broadcast
以上是关于Broadcast发送流程分析的主要内容,如果未能解决你的问题,请参考以下文章
Android系统广播(Broadcast)注册,发送,接收流程解析
android framework开发之广播broadcast源码分析2-千里马