Broadcast(二)registerReceiver时sticky广播

ActivityManagerService.java

registerReceiver最后一段是这个

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);
        BroadcastQueue queue = broadcastQueueForIntent(intent);
        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);
        queue.scheduleBroadcastsLocked();
    }
}

// 发送广播的时候intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
// 就可以把广播放到mFgBroadcastQueue
// 前后台广播主要是超时时间不一样,见[Broadcast (四)有序广播]
BroadcastQueue broadcastQueueForIntent(Intent intent) {
    final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
    if (DEBUG_BROADCAST_BACKGROUND) Slog.i(TAG_BROADCAST,
            "Broadcast intent " + intent + " on "
            + (isFg ? "foreground" : "background") + " queue");
    return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;
}

BroadcastQueue.java

//无序广播队列
final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>();

//有序广播队列
final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();

public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
    mParallelBroadcasts.add(r);
    r.enqueueClockTime = System.currentTimeMillis();
}

public void scheduleBroadcastsLocked() {
    ...
    // 有很多地方都是这种形式,服务端收到通知,通过Handler异步处理,
    // 不至于让客户端挂起太久,服务端处理完毕再发个通知到客户端
    // (这时客户端服务端角色就转换了,也就说app和system进程两边经常都是接到通知后就扔给Handler)
    mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
}

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;
            ...
        }
    }
}

final void processNextBroadcast(boolean fromMsg) {
    //全程保持AMS锁,其他线程(app进程binder通信)都需要等待此方法处理完毕
    synchronized(mService) {
        //step1:处理全部无序广播,遍历动态注册的接收者并通知
        //step2:获取第一条有序广播
        //step3:获取第一个接收者,校验接收者权限
        //step4:设置超时时间,通知接收者
    }
}

registerReceiver的时候只用到了step1
如果有静态注册的接收者,有序广播也会有数据
step234每次只会处理一条广播一个接收者,app onReceive处理完毕会通知system进程,会再次调用processNextBroadcast
其他step在后续sendBroadcast文章分析
processNextBroadcast→step1

        // 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(r);
        }

private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
                                               BroadcastFilter filter, 
                                               boolean ordered, int index) {
    boolean skip = false;
    // 如果发送者设置需要权限,
    // 就检验接收者是否具有发送者所需的权限,
    // 如果没有权限,skip=true
    ...
    if (skip) {
        r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
        return;
    }
    ...
    // If this is not being sent as an ordered broadcast, then we
    // don't want to touch the fields that keep track of the current
    // state of ordered broadcasts.
    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) {
            // Bump hosting application to no longer be in background
            // scheduling class.  Note that we can't do that if there
            // isn't an app...  but we can only be in that case for
            // things that directly call the IActivityManager API, which
            // are already core system stuff so don't matter for this.
            r.curApp = filter.receiverList.app;
            filter.receiverList.app.curReceiver = r;
            mService.updateOomAdjLocked(r.curApp);
        }
    }
    try {
        ...
        performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                new Intent(r.intent), r.resultCode, r.resultData,
                r.resultExtras, r.ordered, r.initialSticky, r.userId);
        ...
    } catch (RemoteException e) {
        ...
    }
}

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) {
            // 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.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 {
        receiver.performReceive(intent, resultCode, data, extras, ordered,
                sticky, sendingUser);
    }
}

一直到结束,并没有设置超时,所以registerReceiver时sticky广播调用onReceive并不会导致ANR(普通广播即sendBroadcast和sendStickyBroadcast的动态注册接收者也只是经过processNextBroadcast→step1)

《Broadcast(二)registerReceiver时sticky广播》

    原文作者:风风风筝
    原文地址: https://www.jianshu.com/p/cb56312f94c9
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞