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

Commit 48ffbabc authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

BroadcastQueue: better state transition logging.

To aid future debugging of the modern stack, include a "reason"
behind each state transition.

Remove outdated TODOs that are either finished or tracked elsewhere,
add misc annotations.

Bug: 254521331
Test: atest FrameworksMockingServicesTests:BroadcastRecordTest
Test: atest FrameworksMockingServicesTests:BroadcastQueueTest
Test: atest FrameworksMockingServicesTests:BroadcastQueueModernImplTest
Change-Id: I307dc86b1935d5ca88a8ca20869cb9120e05bf12
parent f078425b
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@ import android.os.SystemClock;
import android.util.ArraySet;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;

import java.io.PrintWriter;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
@@ -37,6 +39,7 @@ import java.util.concurrent.CountDownLatch;
public class BroadcastLoopers {
    private static final String TAG = "BroadcastLoopers";

    @GuardedBy("sLoopers")
    private static final ArraySet<Looper> sLoopers = new ArraySet<>();

    /**
+31 −29
Original line number Diff line number Diff line
@@ -144,14 +144,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        mRunning = new BroadcastProcessQueue[mConstants.MAX_RUNNING_PROCESS_QUEUES];
    }

    // TODO: add support for replacing pending broadcasts
    // TODO: add support for merging pending broadcasts

    // TODO: consider reordering foreground broadcasts within queue

    // TODO: pause queues when background services are running
    // TODO: pause queues when processes are frozen

    /**
     * Map from UID to per-process broadcast queues. If a UID hosts more than
     * one process, each additional process is stored as a linked list using
@@ -516,7 +508,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        if (queue != null) {
            // If queue was running a broadcast, fail it
            if (queue.isActive()) {
                finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE);
                finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
                        "onApplicationCleanupLocked");
            }

            // Skip any pending registered receivers, since the old process
@@ -668,7 +661,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        // Ignore registered receivers from a previous PID
        if (receiver instanceof BroadcastFilter) {
            mRunningColdStart = null;
            finishReceiverLocked(queue, BroadcastRecord.DELIVERY_SKIPPED);
            finishReceiverLocked(queue, BroadcastRecord.DELIVERY_SKIPPED,
                    "BroadcastFilter for cold app");
            return;
        }

@@ -690,7 +684,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                hostingRecord, zygotePolicyFlags, allowWhileBooting, false);
        if (queue.app == null) {
            mRunningColdStart = null;
            finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE);
            finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
                    "startProcessLocked failed");
            return;
        }
    }
@@ -721,29 +716,30 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        // If someone already finished this broadcast, finish immediately
        final int oldDeliveryState = getDeliveryState(r, index);
        if (isDeliveryStateTerminal(oldDeliveryState)) {
            finishReceiverLocked(queue, oldDeliveryState);
            finishReceiverLocked(queue, oldDeliveryState, "already terminal state");
            return;
        }

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

        // Ignore registered receivers from a previous PID
        if ((receiver instanceof BroadcastFilter)
                && ((BroadcastFilter) receiver).receiverList.pid != app.getPid()) {
            finishReceiverLocked(queue, BroadcastRecord.DELIVERY_SKIPPED);
            finishReceiverLocked(queue, BroadcastRecord.DELIVERY_SKIPPED,
                    "BroadcastFilter for mismatched PID");
            return;
        }

@@ -778,7 +774,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        }

        if (DEBUG_BROADCAST) logv("Scheduling " + r + " to warm " + app);
        setDeliveryState(queue, app, r, index, receiver, BroadcastRecord.DELIVERY_SCHEDULED);
        setDeliveryState(queue, app, r, index, receiver, BroadcastRecord.DELIVERY_SCHEDULED,
                "scheduleReceiverWarmLocked");

        final IApplicationThread thread = app.getOnewayThread();
        if (thread != null) {
@@ -793,7 +790,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                    // TODO: consider making registered receivers of unordered
                    // broadcasts report results to detect ANRs
                    if (assumeDelivered) {
                        finishReceiverLocked(queue, BroadcastRecord.DELIVERY_DELIVERED);
                        finishReceiverLocked(queue, BroadcastRecord.DELIVERY_DELIVERED,
                                "assuming delivered");
                    }
                } else {
                    notifyScheduleReceiver(app, r, (ResolveInfo) receiver);
@@ -807,10 +805,11 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                logw(msg);
                app.scheduleCrashLocked(msg, CannotDeliverBroadcastException.TYPE_ID, null);
                app.setKilled(true);
                finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE);
                finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE, "remote app");
            }
        } else {
            finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE);
            finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
                    "missing IApplicationThread");
        }
    }

@@ -854,7 +853,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
    }

    private void deliveryTimeoutHardLocked(@NonNull BroadcastProcessQueue queue) {
        finishReceiverLocked(queue, BroadcastRecord.DELIVERY_TIMEOUT);
        finishReceiverLocked(queue, BroadcastRecord.DELIVERY_TIMEOUT,
                "deliveryTimeoutHardLocked");
    }

    @Override
@@ -881,16 +881,16 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
            if (r.resultAbort) {
                for (int i = r.terminalCount + 1; i < r.receivers.size(); i++) {
                    setDeliveryState(null, null, r, i, r.receivers.get(i),
                            BroadcastRecord.DELIVERY_SKIPPED);
                            BroadcastRecord.DELIVERY_SKIPPED, "resultAbort");
                }
            }
        }

        return finishReceiverLocked(queue, BroadcastRecord.DELIVERY_DELIVERED);
        return finishReceiverLocked(queue, BroadcastRecord.DELIVERY_DELIVERED, "remote app");
    }

    private boolean finishReceiverLocked(@NonNull BroadcastProcessQueue queue,
            @DeliveryState int deliveryState) {
            @DeliveryState int deliveryState, @NonNull String reason) {
        checkState(queue.isActive(), "isActive");

        final ProcessRecord app = queue.app;
@@ -898,7 +898,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        final int index = queue.getActiveIndex();
        final Object receiver = r.receivers.get(index);

        setDeliveryState(queue, app, r, index, receiver, deliveryState);
        setDeliveryState(queue, app, r, index, receiver, deliveryState, reason);

        if (deliveryState == BroadcastRecord.DELIVERY_TIMEOUT) {
            r.anrCount++;
@@ -945,7 +945,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
     */
    private void setDeliveryState(@Nullable BroadcastProcessQueue queue,
            @Nullable ProcessRecord app, @NonNull BroadcastRecord r, int index,
            @NonNull Object receiver, @DeliveryState int newDeliveryState) {
            @NonNull Object receiver, @DeliveryState int newDeliveryState, String reason) {
        final int oldDeliveryState = getDeliveryState(r, index);

        // Only apply state when we haven't already reached a terminal state;
@@ -973,7 +973,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                logw("Delivery state of " + r + " to " + receiver
                        + " via " + app + " changed from "
                        + deliveryStateToString(oldDeliveryState) + " to "
                        + deliveryStateToString(newDeliveryState));
                        + deliveryStateToString(newDeliveryState) + " because " + reason);
            }

            r.terminalCount++;
@@ -1063,7 +1063,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
     * of it matching a predicate.
     */
    private final BroadcastConsumer mBroadcastConsumerSkip = (r, i) -> {
        setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_SKIPPED);
        setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_SKIPPED,
                "mBroadcastConsumerSkip");
    };

    /**
@@ -1071,7 +1072,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
     * cancelled, usually as a result of it matching a predicate.
     */
    private final BroadcastConsumer mBroadcastConsumerSkipAndCanceled = (r, i) -> {
        setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_SKIPPED);
        setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_SKIPPED,
                "mBroadcastConsumerSkipAndCanceled");
        r.resultCode = Activity.RESULT_CANCELED;
        r.resultData = null;
        r.resultExtras = null;