Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ecacd186 authored by Lee Shombert's avatar Lee Shombert
Browse files

Minor refactoring to the modern queue

Bug: 249161784

This contains some small changes to the modern queue to prepare for
larger changes with batched broadcasts.

 1. The BroadcastRecord is updated before it recorded in the history.
    This allows the history to make a copy and not miss any
    information.

 2. The logic in scheduleReceiverWarmLocked() is factored into
    separate methods that can be called from other code.

 3. finishReceiverLocked() takes an explicit BroadcastRecord and
    index.  The logic to continue scheduling receivers has been pulled
    out.

The changes are designed to have no functional effect.

Test: atest
 * FrameworksMockingServicesTests:BroadcastQueueTest

Change-Id: I4a154ebfa5c0f506d59fe81504e055366ed5fc81
parent 37ab04b0
Loading
Loading
Loading
Loading
+81 −24
Original line number Diff line number Diff line
@@ -220,10 +220,19 @@ class BroadcastQueueModernImpl extends BroadcastQueue {

    private void enqueueFinishReceiver(@NonNull BroadcastProcessQueue queue,
            @DeliveryState int deliveryState, @NonNull String reason) {
        enqueueFinishReceiver(queue, queue.getActive(), queue.getActiveIndex(),
                deliveryState, reason);
    }

    private void enqueueFinishReceiver(@NonNull BroadcastProcessQueue queue,
            @NonNull BroadcastRecord r, int index,
            @DeliveryState int deliveryState, @NonNull String reason) {
        final SomeArgs args = SomeArgs.obtain();
        args.arg1 = queue;
        args.argi1 = deliveryState;
        args.arg2 = reason;
        args.arg3 = r;
        args.argi2 = index;
        mLocalHandler.sendMessage(Message.obtain(mLocalHandler, MSG_FINISH_RECEIVER, args));
    }

@@ -271,8 +280,10 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                    final BroadcastProcessQueue queue = (BroadcastProcessQueue) args.arg1;
                    final int deliveryState = args.argi1;
                    final String reason = (String) args.arg2;
                    final BroadcastRecord r = (BroadcastRecord) args.arg3;
                    final int index = args.argi2;
                    args.recycle();
                    finishReceiverLocked(queue, deliveryState, reason);
                    finishReceiverLocked(queue, deliveryState, reason, r, index);
                }
                return true;
            }
@@ -729,10 +740,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
    private void scheduleReceiverWarmLocked(@NonNull BroadcastProcessQueue queue) {
        checkState(queue.isActive(), "isActive");

        final ProcessRecord app = queue.app;
        final BroadcastRecord r = queue.getActive();
        final int index = queue.getActiveIndex();
        final Object receiver = r.receivers.get(index);

        if (r.terminalCount == 0) {
            r.dispatchTime = SystemClock.uptimeMillis();
@@ -740,26 +749,40 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
            r.dispatchClockTime = System.currentTimeMillis();
        }

        // If someone already finished this broadcast, finish immediately
        if (maybeSkipReceiver(queue, r, index)) {
            return;
        }
        dispatchReceivers(queue, r, index);
    }

    /**
     * Examine a receiver and possibly skip it.  The method returns true if the receiver is
     * skipped (and therefore no more work is required).
     */
    private boolean maybeSkipReceiver(BroadcastProcessQueue queue, BroadcastRecord r, int index) {
        final int oldDeliveryState = getDeliveryState(r, index);
        final ProcessRecord app = queue.app;
        final Object receiver = r.receivers.get(index);

        // If someone already finished this broadcast, finish immediately
        if (isDeliveryStateTerminal(oldDeliveryState)) {
            enqueueFinishReceiver(queue, oldDeliveryState, "already terminal state");
            return;
            return true;
        }

        // Consider additional cases where we'd want to finish immediately
        if (app.isInFullBackup()) {
            enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED, "isInFullBackup");
            return;
            return true;
        }
        if (mSkipPolicy.shouldSkip(r, receiver)) {
            enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED, "mSkipPolicy");
            return;
            return true;
        }
        final Intent receiverIntent = r.getReceiverIntent(receiver);
        if (receiverIntent == null) {
            enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED, "getReceiverIntent");
            return;
            return true;
        }

        // Ignore registered receivers from a previous PID
@@ -767,12 +790,29 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                && ((BroadcastFilter) receiver).receiverList.pid != app.getPid()) {
            enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED,
                    "BroadcastFilter for mismatched PID");
            return;
            return true;
        }
        // The receiver was not handled in this method.
        return false;
    }

    /**
     * Return true if this receiver should be assumed to have been delivered.
     */
    private boolean isAssumedDelivered(BroadcastRecord r, int index) {
        return (r.receivers.get(index) instanceof BroadcastFilter) && !r.ordered;
    }

    /**
     * A receiver is about to be dispatched.  Start ANR timers, if necessary.
     */
    private void dispatchReceivers(BroadcastProcessQueue queue, BroadcastRecord r, int index) {
        final ProcessRecord app = queue.app;
        final Object receiver = r.receivers.get(index);

        // Skip ANR tracking early during boot, when requested, or when we
        // immediately assume delivery success
        final boolean assumeDelivered = (receiver instanceof BroadcastFilter) && !r.ordered;
        final boolean assumeDelivered = isAssumedDelivered(r, index);
        if (mService.mProcessesReady && !r.timeoutExempt && !assumeDelivered) {
            queue.lastCpuDelayTime = queue.app.getCpuDelayTime();

@@ -805,6 +845,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        setDeliveryState(queue, app, r, index, receiver, BroadcastRecord.DELIVERY_SCHEDULED,
                "scheduleReceiverWarmLocked");

        final Intent receiverIntent = r.getReceiverIntent(receiver);
        final IApplicationThread thread = app.getOnewayThread();
        if (thread != null) {
            try {
@@ -920,6 +961,19 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        return finishReceiverLocked(queue, BroadcastRecord.DELIVERY_DELIVERED, "remote app");
    }

    /**
     * Return true if there are more broadcasts in the queue and the queue is runnable.
     */
    private boolean shouldContinueScheduling(@NonNull BroadcastProcessQueue queue) {
        // If we've made reasonable progress, periodically retire ourselves to
        // avoid starvation of other processes and stack overflow when a
        // broadcast is immediately finished without waiting
        final boolean shouldRetire =
                (queue.getActiveCountSinceIdle() >= mConstants.MAX_RUNNING_ACTIVE_BROADCASTS);

        return queue.isRunnable() && queue.isProcessWarm() && !shouldRetire;
    }

    private boolean finishReceiverLocked(@NonNull BroadcastProcessQueue queue,
            @DeliveryState int deliveryState, @NonNull String reason) {
        if (!queue.isActive()) {
@@ -927,10 +981,21 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
            return false;
        }

        final int cookie = traceBegin("finishReceiver");
        final ProcessRecord app = queue.app;
        final BroadcastRecord r = queue.getActive();
        final int index = queue.getActiveIndex();
        return finishReceiverLocked(queue, deliveryState, reason, r, index);
    }

    private boolean finishReceiverLocked(@NonNull BroadcastProcessQueue queue,
            @DeliveryState int deliveryState, @NonNull String reason,
            BroadcastRecord r, int index) {
        if (!queue.isActive()) {
            logw("Ignoring finish; no active broadcast for " + queue);
            return false;
        }

        final int cookie = traceBegin("finishReceiver");
        final ProcessRecord app = queue.app;
        final Object receiver = r.receivers.get(index);

        setDeliveryState(queue, app, r, index, receiver, deliveryState, reason);
@@ -945,18 +1010,11 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
            mLocalHandler.removeMessages(MSG_DELIVERY_TIMEOUT_HARD, queue);
        }

        // If we've made reasonable progress, periodically retire ourselves to
        // avoid starvation of other processes and stack overflow when a
        // broadcast is immediately finished without waiting
        final boolean shouldRetire =
                (queue.getActiveCountSinceIdle() >= mConstants.MAX_RUNNING_ACTIVE_BROADCASTS);

        final boolean res;
        if (queue.isRunnable() && queue.isProcessWarm() && !shouldRetire) {
        final boolean res = shouldContinueScheduling(queue);
        if (res) {
            // We're on a roll; move onto the next broadcast for this process
            queue.makeActiveNextPending();
            scheduleReceiverWarmLocked(queue);
            res = true;
        } else {
            // We've drained running broadcasts; maybe move back to runnable
            queue.makeActiveIdle();
@@ -970,7 +1028,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
            // Tell other OS components that app is not actively running, giving
            // a chance to update OOM adjustment
            notifyStoppedRunning(queue);
            res = false;
        }
        traceEnd(cookie);
        return res;
@@ -1442,10 +1499,10 @@ class BroadcastQueueModernImpl extends BroadcastQueue {

    private void notifyFinishBroadcast(@NonNull BroadcastRecord r) {
        mService.notifyBroadcastFinishedLocked(r);
        mHistory.addBroadcastToHistoryLocked(r);

        r.finishTime = SystemClock.uptimeMillis();
        r.nextReceiver = r.receivers.size();
        mHistory.addBroadcastToHistoryLocked(r);

        BroadcastQueueImpl.logBootCompletedBroadcastCompletionLatencyIfPossible(r);

        if (r.intent.getComponent() == null && r.intent.getPackage() == null