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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值