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

Commit 16344766 authored by Sudheer Shanka's avatar Sudheer Shanka Committed by Android (Google) Code Review
Browse files

Merge changes Ibd70ef40,Ibcb36ebf

* changes:
  Don't let offload broadcasts to be starved.
  Don't wait for message queues to become idle in wait-for-barrier.
parents 73df089d c37dea91
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -18324,7 +18324,7 @@ public class ActivityManagerService extends IActivityManager.Stub
    public void waitForBroadcastBarrier(@Nullable PrintWriter pw) {
    public void waitForBroadcastBarrier(@Nullable PrintWriter pw) {
        enforceCallingPermission(permission.DUMP, "waitForBroadcastBarrier()");
        enforceCallingPermission(permission.DUMP, "waitForBroadcastBarrier()");
        BroadcastLoopers.waitForIdle(pw);
        BroadcastLoopers.waitForBarrier(pw);
        for (BroadcastQueue queue : mBroadcastQueues) {
        for (BroadcastQueue queue : mBroadcastQueues) {
            queue.waitForBarrier(pw);
            queue.waitForBarrier(pw);
        }
        }
+22 −0
Original line number Original line Diff line number Diff line
@@ -153,11 +153,26 @@ public class BroadcastConstants {
            "bcast_extra_running_urgent_process_queues";
            "bcast_extra_running_urgent_process_queues";
    private static final int DEFAULT_EXTRA_RUNNING_URGENT_PROCESS_QUEUES = 1;
    private static final int DEFAULT_EXTRA_RUNNING_URGENT_PROCESS_QUEUES = 1;


    /**
     * For {@link BroadcastQueueModernImpl}: Maximum number of consecutive urgent
     * broadcast dispatches allowed before letting broadcasts in lower priority queue
     * to be scheduled in order to avoid starvation.
     */
    public int MAX_CONSECUTIVE_URGENT_DISPATCHES = DEFAULT_MAX_CONSECUTIVE_URGENT_DISPATCHES;
    public int MAX_CONSECUTIVE_URGENT_DISPATCHES = DEFAULT_MAX_CONSECUTIVE_URGENT_DISPATCHES;
    private static final String KEY_MAX_CONSECUTIVE_URGENT_DISPATCHES =
    private static final String KEY_MAX_CONSECUTIVE_URGENT_DISPATCHES =
            "bcast_max_consecutive_urgent_dispatches";
            "bcast_max_consecutive_urgent_dispatches";
    private static final int DEFAULT_MAX_CONSECUTIVE_URGENT_DISPATCHES = 3;
    private static final int DEFAULT_MAX_CONSECUTIVE_URGENT_DISPATCHES = 3;


    /**
     * For {@link BroadcastQueueModernImpl}: Maximum number of consecutive normal
     * broadcast dispatches allowed before letting broadcasts in lower priority queue
     * to be scheduled in order to avoid starvation.
     */
    public int MAX_CONSECUTIVE_NORMAL_DISPATCHES = DEFAULT_MAX_CONSECUTIVE_NORMAL_DISPATCHES;
    private static final String KEY_MAX_CONSECUTIVE_NORMAL_DISPATCHES =
            "bcast_max_consecutive_normal_dispatches";
    private static final int DEFAULT_MAX_CONSECUTIVE_NORMAL_DISPATCHES = 10;

    /**
    /**
     * For {@link BroadcastQueueModernImpl}: Maximum number of active broadcasts
     * For {@link BroadcastQueueModernImpl}: Maximum number of active broadcasts
     * to dispatch to a "running" process queue before we retire them back to
     * to dispatch to a "running" process queue before we retire them back to
@@ -341,6 +356,9 @@ public class BroadcastConstants {
            MAX_CONSECUTIVE_URGENT_DISPATCHES = getDeviceConfigInt(
            MAX_CONSECUTIVE_URGENT_DISPATCHES = getDeviceConfigInt(
                    KEY_MAX_CONSECUTIVE_URGENT_DISPATCHES,
                    KEY_MAX_CONSECUTIVE_URGENT_DISPATCHES,
                    DEFAULT_MAX_CONSECUTIVE_URGENT_DISPATCHES);
                    DEFAULT_MAX_CONSECUTIVE_URGENT_DISPATCHES);
            MAX_CONSECUTIVE_NORMAL_DISPATCHES = getDeviceConfigInt(
                    KEY_MAX_CONSECUTIVE_NORMAL_DISPATCHES,
                    DEFAULT_MAX_CONSECUTIVE_NORMAL_DISPATCHES);
            MAX_RUNNING_ACTIVE_BROADCASTS = getDeviceConfigInt(KEY_MAX_RUNNING_ACTIVE_BROADCASTS,
            MAX_RUNNING_ACTIVE_BROADCASTS = getDeviceConfigInt(KEY_MAX_RUNNING_ACTIVE_BROADCASTS,
                    DEFAULT_MAX_RUNNING_ACTIVE_BROADCASTS);
                    DEFAULT_MAX_RUNNING_ACTIVE_BROADCASTS);
            MAX_PENDING_BROADCASTS = getDeviceConfigInt(KEY_MAX_PENDING_BROADCASTS,
            MAX_PENDING_BROADCASTS = getDeviceConfigInt(KEY_MAX_PENDING_BROADCASTS,
@@ -396,6 +414,10 @@ public class BroadcastConstants {
                    TimeUtils.formatDuration(DELAY_URGENT_MILLIS)).println();
                    TimeUtils.formatDuration(DELAY_URGENT_MILLIS)).println();
            pw.print(KEY_MAX_HISTORY_COMPLETE_SIZE, MAX_HISTORY_COMPLETE_SIZE).println();
            pw.print(KEY_MAX_HISTORY_COMPLETE_SIZE, MAX_HISTORY_COMPLETE_SIZE).println();
            pw.print(KEY_MAX_HISTORY_SUMMARY_SIZE, MAX_HISTORY_SUMMARY_SIZE).println();
            pw.print(KEY_MAX_HISTORY_SUMMARY_SIZE, MAX_HISTORY_SUMMARY_SIZE).println();
            pw.print(KEY_MAX_CONSECUTIVE_URGENT_DISPATCHES,
                    MAX_CONSECUTIVE_URGENT_DISPATCHES).println();
            pw.print(KEY_MAX_CONSECUTIVE_NORMAL_DISPATCHES,
                    MAX_CONSECUTIVE_NORMAL_DISPATCHES).println();
            pw.decreaseIndent();
            pw.decreaseIndent();
            pw.println();
            pw.println();
        }
        }
+32 −5
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.am;


import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.os.Handler;
import android.os.Looper;
import android.os.Looper;
import android.os.Message;
import android.os.Message;
import android.os.MessageQueue;
import android.os.MessageQueue;
@@ -30,6 +31,7 @@ import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.util.Objects;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CountDownLatch;
import java.util.function.BiConsumer;


/**
/**
 * Collection of {@link Looper} that are known to be used for broadcast dispatch
 * Collection of {@link Looper} that are known to be used for broadcast dispatch
@@ -73,19 +75,44 @@ public class BroadcastLoopers {
     * still in the future are ignored for the purposes of the idle test.
     * still in the future are ignored for the purposes of the idle test.
     */
     */
    public static void waitForIdle(@Nullable PrintWriter pw) {
    public static void waitForIdle(@Nullable PrintWriter pw) {
        waitForCondition(pw, (looper, latch) -> {
            final MessageQueue queue = looper.getQueue();
            queue.addIdleHandler(() -> {
                latch.countDown();
                return false;
            });
        });
    }

    /**
     * Wait for all registered {@link Looper} instances to handle currently waiting messages.
     * Note that {@link Message#when} still in the future are ignored for the purposes
     * of the idle test.
     */
    public static void waitForBarrier(@Nullable PrintWriter pw) {
        waitForCondition(pw, (looper, latch) -> {
            (new Handler(looper)).post(() -> {
                latch.countDown();
            });
        });
    }

    /**
     * Wait for all registered {@link Looper} instances to meet a certain condition.
     */
    private static void waitForCondition(@Nullable PrintWriter pw,
            @NonNull BiConsumer<Looper, CountDownLatch> condition) {
        final CountDownLatch latch;
        final CountDownLatch latch;
        synchronized (sLoopers) {
        synchronized (sLoopers) {
            final int N = sLoopers.size();
            final int N = sLoopers.size();
            latch = new CountDownLatch(N);
            latch = new CountDownLatch(N);
            for (int i = 0; i < N; i++) {
            for (int i = 0; i < N; i++) {
                final MessageQueue queue = sLoopers.valueAt(i).getQueue();
                final Looper looper = sLoopers.valueAt(i);
                final MessageQueue queue = looper.getQueue();
                if (queue.isIdle()) {
                if (queue.isIdle()) {
                    latch.countDown();
                    latch.countDown();
                } else {
                } else {
                    queue.addIdleHandler(() -> {
                    condition.accept(looper, latch);
                        latch.countDown();
                        return false;
                    });
                }
                }
            }
            }
        }
        }
+55 −34
Original line number Original line Diff line number Diff line
@@ -152,6 +152,12 @@ class BroadcastProcessQueue {
     */
     */
    private int mActiveCountConsecutiveUrgent;
    private int mActiveCountConsecutiveUrgent;


    /**
     * Number of consecutive normal broadcasts that have been dispatched
     * since the last offload dispatch.
     */
    private int mActiveCountConsecutiveNormal;

    /**
    /**
     * Count of pending broadcasts of these various flavors.
     * Count of pending broadcasts of these various flavors.
     */
     */
@@ -551,48 +557,63 @@ class BroadcastProcessQueue {
     * Will thrown an exception if there are no pending broadcasts; relies on
     * Will thrown an exception if there are no pending broadcasts; relies on
     * {@link #isEmpty()} being false.
     * {@link #isEmpty()} being false.
     */
     */
    SomeArgs removeNextBroadcast() {
    private @Nullable SomeArgs removeNextBroadcast() {
        final ArrayDeque<SomeArgs> queue = queueForNextBroadcast();
        final ArrayDeque<SomeArgs> queue = queueForNextBroadcast();
        if (queue == mPendingUrgent) {
        if (queue == mPendingUrgent) {
            mActiveCountConsecutiveUrgent++;
            mActiveCountConsecutiveUrgent++;
        } else {
        } else if (queue == mPending) {
            mActiveCountConsecutiveUrgent = 0;
            mActiveCountConsecutiveNormal++;
        } else if (queue == mPendingOffload) {
            mActiveCountConsecutiveUrgent = 0;
            mActiveCountConsecutiveUrgent = 0;
            mActiveCountConsecutiveNormal = 0;
        }
        }
        return queue.removeFirst();
        return !isQueueEmpty(queue) ? queue.removeFirst() : null;
    }
    }


    @Nullable ArrayDeque<SomeArgs> queueForNextBroadcast() {
    @Nullable ArrayDeque<SomeArgs> queueForNextBroadcast() {
        ArrayDeque<SomeArgs> nextUrgent = mPendingUrgent.isEmpty() ? null : mPendingUrgent;
        final ArrayDeque<SomeArgs> nextNormal = queueForNextBroadcast(
        ArrayDeque<SomeArgs> nextNormal = null;
                mPending, mPendingOffload,
        if (!mPending.isEmpty()) {
                mActiveCountConsecutiveNormal, constants.MAX_CONSECUTIVE_NORMAL_DISPATCHES);
            nextNormal = mPending;
        final ArrayDeque<SomeArgs> nextBroadcastQueue = queueForNextBroadcast(
        } else if (!mPendingOffload.isEmpty()) {
                mPendingUrgent, nextNormal,
            nextNormal = mPendingOffload;
                mActiveCountConsecutiveUrgent, constants.MAX_CONSECUTIVE_URGENT_DISPATCHES);
        }
        return nextBroadcastQueue;
        // nothing urgent pending, no further decisionmaking
    }
        if (nextUrgent == null) {

            return nextNormal;
    private @Nullable ArrayDeque<SomeArgs> queueForNextBroadcast(
        }
            @Nullable ArrayDeque<SomeArgs> highPriorityQueue,
        // nothing but urgent pending, also no further decisionmaking
            @Nullable ArrayDeque<SomeArgs> lowPriorityQueue,
        if (nextNormal == null) {
            int consecutiveHighPriorityCount,
            return nextUrgent;
            int maxHighPriorityDispatchLimit) {
        }
        // nothing high priority pending, no further decisionmaking

        if (isQueueEmpty(highPriorityQueue)) {
        // Starvation mitigation: although we prioritize urgent broadcasts by default,
            return lowPriorityQueue;
        // we allow non-urgent deliveries to make steady progress even if urgent
        }
        // broadcasts are arriving faster than they can be dispatched.
        // nothing but high priority pending, also no further decisionmaking
        if (isQueueEmpty(lowPriorityQueue)) {
            return highPriorityQueue;
        }

        // Starvation mitigation: although we prioritize high priority queues by default,
        // we allow low priority queues to make steady progress even if broadcasts in
        // high priority queue are arriving faster than they can be dispatched.
        //
        //
        // We do not try to defer to the next non-urgent broadcast if that broadcast
        // We do not try to defer to the next broadcast in low priority queues if that broadcast
        // is ordered and still blocked on delivery to other recipients.
        // is ordered and still blocked on delivery to other recipients.
        final SomeArgs nextNormalArgs = nextNormal.peekFirst();
        final SomeArgs nextLPArgs = lowPriorityQueue.peekFirst();
        final BroadcastRecord rNormal = (BroadcastRecord) nextNormalArgs.arg1;
        final BroadcastRecord nextLPRecord = (BroadcastRecord) nextLPArgs.arg1;
        final int nextNormalIndex = nextNormalArgs.argi1;
        final int nextLPRecordIndex = nextLPArgs.argi1;
        final BroadcastRecord rUrgent = (BroadcastRecord) nextUrgent.peekFirst().arg1;
        final BroadcastRecord nextHPRecord = (BroadcastRecord) highPriorityQueue.peekFirst().arg1;
        final boolean canTakeNormal =
        final boolean isLPQueueEligible =
                mActiveCountConsecutiveUrgent >= constants.MAX_CONSECUTIVE_URGENT_DISPATCHES
                consecutiveHighPriorityCount >= maxHighPriorityDispatchLimit
                        && rNormal.enqueueTime <= rUrgent.enqueueTime
                        && nextLPRecord.enqueueTime <= nextHPRecord.enqueueTime
                        && !blockedOnOrderedDispatch(rNormal, nextNormalIndex);
                        && !blockedOnOrderedDispatch(nextLPRecord, nextLPRecordIndex);
        return canTakeNormal ? nextNormal : nextUrgent;
        return isLPQueueEligible ? lowPriorityQueue : highPriorityQueue;
    }

    private static boolean isQueueEmpty(@Nullable ArrayDeque<SomeArgs> queue) {
        return (queue == null || queue.isEmpty());
    }
    }


    /**
    /**
@@ -600,13 +621,13 @@ class BroadcastProcessQueue {
     */
     */
    @Nullable SomeArgs peekNextBroadcast() {
    @Nullable SomeArgs peekNextBroadcast() {
        ArrayDeque<SomeArgs> queue = queueForNextBroadcast();
        ArrayDeque<SomeArgs> queue = queueForNextBroadcast();
        return (queue != null) ? queue.peekFirst() : null;
        return !isQueueEmpty(queue) ? queue.peekFirst() : null;
    }
    }


    @VisibleForTesting
    @VisibleForTesting
    @Nullable BroadcastRecord peekNextBroadcastRecord() {
    @Nullable BroadcastRecord peekNextBroadcastRecord() {
        ArrayDeque<SomeArgs> queue = queueForNextBroadcast();
        ArrayDeque<SomeArgs> queue = queueForNextBroadcast();
        return (queue != null) ? (BroadcastRecord) queue.peekFirst().arg1 : null;
        return !isQueueEmpty(queue) ? (BroadcastRecord) queue.peekFirst().arg1 : null;
    }
    }


    /**
    /**
+67 −0
Original line number Original line Diff line number Diff line
@@ -591,6 +591,73 @@ public class BroadcastQueueModernImplTest {
        assertEquals(Intent.ACTION_ALARM_CHANGED, queue.getActive().intent.getAction());
        assertEquals(Intent.ACTION_ALARM_CHANGED, queue.getActive().intent.getAction());
    }
    }


    /**
     * Verify that offload broadcasts are not starved because of broadcasts in higher priority
     * queues.
     */
    @Test
    public void testOffloadStarvation() {
        final BroadcastOptions optInteractive = BroadcastOptions.makeBasic();
        optInteractive.setInteractive(true);

        mConstants.MAX_CONSECUTIVE_URGENT_DISPATCHES = 1;
        mConstants.MAX_CONSECUTIVE_NORMAL_DISPATCHES = 2;
        final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
                PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));

        // mix of broadcasts, with more than 2 normal
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_BOOT_COMPLETED)
                        .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)), 0);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_PACKAGE_CHANGED)
                        .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_ALARM_CHANGED)), 0);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_LOCALE_CHANGED)
                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_APPLICATION_PREFERENCES),
                        optInteractive), 0);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE),
                        optInteractive), 0);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_INPUT_METHOD_CHANGED)
                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_NEW_OUTGOING_CALL),
                        optInteractive), 0);

        queue.makeActiveNextPending();
        assertEquals(Intent.ACTION_LOCALE_CHANGED, queue.getActive().intent.getAction());
        // after MAX_CONSECUTIVE_URGENT_DISPATCHES expect an ordinary one next
        queue.makeActiveNextPending();
        assertEquals(Intent.ACTION_TIMEZONE_CHANGED, queue.getActive().intent.getAction());
        // and then back to prioritizing urgent ones
        queue.makeActiveNextPending();
        assertEquals(Intent.ACTION_APPLICATION_PREFERENCES, queue.getActive().intent.getAction());
        // after MAX_CONSECUTIVE_URGENT_DISPATCHES, again an ordinary one next
        queue.makeActiveNextPending();
        assertEquals(Intent.ACTION_ALARM_CHANGED, queue.getActive().intent.getAction());
        // and then back to prioritizing urgent ones
        queue.makeActiveNextPending();
        assertEquals(AppWidgetManager.ACTION_APPWIDGET_UPDATE,
                queue.getActive().intent.getAction());
        // after MAX_CONSECUTIVE_URGENT_DISPATCHES and MAX_CONSECUTIVE_NORMAL_DISPATCHES,
        // expect an offload one
        queue.makeActiveNextPending();
        assertEquals(Intent.ACTION_BOOT_COMPLETED, queue.getActive().intent.getAction());
        // and then back to prioritizing urgent ones
        queue.makeActiveNextPending();
        assertEquals(Intent.ACTION_INPUT_METHOD_CHANGED, queue.getActive().intent.getAction());
    }

    /**
    /**
     * Verify that sending a broadcast that removes any matching pending
     * Verify that sending a broadcast that removes any matching pending
     * broadcasts is applied as expected.
     * broadcasts is applied as expected.