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

Commit 125e3687 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

BroadcastQueue: constants via DeviceConfig.

Move our initial set of configuration knobs to be loaded and updated
via DeviceConfig inside BroadcastConstants.

This leaves BroadcastConstants with a mix of queue-specific values
and global values; we leave TODOs to detangle this in the future.

Bug: 245771249
Test: atest FrameworksMockingServicesTests:BroadcastQueueTest
Change-Id: I367d23eedacf132759cc7e4b6dab0e07da6e2253
parent 7dda4b4a
Loading
Loading
Loading
Loading
+53 −3
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.am;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.compat.annotation.Overridable;
@@ -24,6 +25,8 @@ import android.content.ContentResolver;
import android.database.ContentObserver;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.KeyValueListParser;
import android.util.Slog;
@@ -39,6 +42,9 @@ import java.lang.annotation.RetentionPolicy;
public class BroadcastConstants {
    private static final String TAG = "BroadcastConstants";

    // TODO: migrate remaining constants to be loaded from DeviceConfig
    // TODO: migrate fg/bg values into single constants instance

    // Value element names within the Settings record
    static final String KEY_TIMEOUT = "bcast_timeout";
    static final String KEY_SLOW_TIME = "bcast_slow_time";
@@ -115,6 +121,35 @@ public class BroadcastConstants {
    // started its process can start a background activity.
    public long ALLOW_BG_ACTIVITY_START_TIMEOUT = DEFAULT_ALLOW_BG_ACTIVITY_START_TIMEOUT;

    /**
     * For {@link BroadcastQueueModernImpl}: Maximum number of process queues to
     * dispatch broadcasts to simultaneously.
     */
    public int MAX_RUNNING_PROCESS_QUEUES = DEFAULT_MAX_RUNNING_PROCESS_QUEUES;
    private static final int DEFAULT_MAX_RUNNING_PROCESS_QUEUES = 4;

    /**
     * For {@link BroadcastQueueModernImpl}: Maximum number of active broadcasts
     * to dispatch to a "running" process queue before we retire them back to
     * being "runnable" to give other processes a chance to run.
     */
    public int MAX_RUNNING_ACTIVE_BROADCASTS = DEFAULT_MAX_RUNNING_ACTIVE_BROADCASTS;
    private static final int DEFAULT_MAX_RUNNING_ACTIVE_BROADCASTS = 16;

    /**
     * For {@link BroadcastQueueModernImpl}: Default delay to apply to normal
     * broadcasts, giving a chance for debouncing of rapidly changing events.
     */
    public long DELAY_NORMAL_MILLIS = DEFAULT_DELAY_NORMAL_MILLIS;
    private static final long DEFAULT_DELAY_NORMAL_MILLIS = 10_000 * Build.HW_TIMEOUT_MULTIPLIER;

    /**
     * For {@link BroadcastQueueModernImpl}: Default delay to apply to
     * broadcasts targeting cached applications.
     */
    public long DELAY_CACHED_MILLIS = DEFAULT_DELAY_CACHED_MILLIS;
    private static final long DEFAULT_DELAY_CACHED_MILLIS = 30_000 * Build.HW_TIMEOUT_MULTIPLIER;

    // Settings override tracking for this instance
    private String mSettingsKey;
    private SettingsObserver mSettingsObserver;
@@ -128,7 +163,7 @@ public class BroadcastConstants {

        @Override
        public void onChange(boolean selfChange) {
            updateConstants();
            updateSettingsConstants();
        }
    }

@@ -148,11 +183,15 @@ public class BroadcastConstants {
        mSettingsObserver = new SettingsObserver(handler);
        mResolver.registerContentObserver(Settings.Global.getUriFor(mSettingsKey),
                false, mSettingsObserver);
        updateSettingsConstants();

        updateConstants();
        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                new HandlerExecutor(handler), this::updateDeviceConfigConstants);
        updateDeviceConfigConstants(
                DeviceConfig.getProperties(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER));
    }

    private void updateConstants() {
    private void updateSettingsConstants() {
        synchronized (mParser) {
            try {
                mParser.setString(Settings.Global.getString(mResolver, mSettingsKey));
@@ -173,6 +212,17 @@ public class BroadcastConstants {
        }
    }

    private void updateDeviceConfigConstants(@NonNull DeviceConfig.Properties properties) {
        MAX_RUNNING_PROCESS_QUEUES = properties.getInt("bcast_max_running_process_queues",
                DEFAULT_MAX_RUNNING_PROCESS_QUEUES);
        MAX_RUNNING_ACTIVE_BROADCASTS = properties.getInt("bcast_max_running_active_broadcasts",
                DEFAULT_MAX_RUNNING_ACTIVE_BROADCASTS);
        DELAY_NORMAL_MILLIS = properties.getLong("bcast_delay_normal_millis",
                DEFAULT_DELAY_NORMAL_MILLIS);
        DELAY_CACHED_MILLIS = properties.getLong("bcast_delay_cached_millis",
                DEFAULT_DELAY_CACHED_MILLIS);
    }

    /**
     * Standard dumpsys support; invoked from BroadcastQueue dump
     */
+8 −17
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import com.android.server.am.BroadcastRecord.DeliveryState;

import java.util.ArrayDeque;
import java.util.Iterator;
import java.util.Objects;
import java.util.function.BiPredicate;

/**
@@ -47,19 +48,7 @@ import java.util.function.BiPredicate;
 * dispatched.
 */
class BroadcastProcessQueue {
    /**
     * Default delay to apply to background broadcasts, giving a chance for
     * debouncing of rapidly changing events.
     */
    // TODO: shift hard-coded defaults to BroadcastConstants
    private static final long DELAY_DEFAULT_MILLIS = 10_000;

    /**
     * Default delay to apply to broadcasts targeting cached applications.
     */
    // TODO: shift hard-coded defaults to BroadcastConstants
    private static final long DELAY_CACHED_MILLIS = 30_000;

    final @NonNull BroadcastConstants constants;
    final @NonNull String processName;
    final int uid;

@@ -129,8 +118,10 @@ class BroadcastProcessQueue {

    private boolean mProcessCached;

    public BroadcastProcessQueue(@NonNull String processName, int uid) {
        this.processName = processName;
    public BroadcastProcessQueue(@NonNull BroadcastConstants constants,
            @NonNull String processName, int uid) {
        this.constants = Objects.requireNonNull(constants);
        this.processName = Objects.requireNonNull(processName);
        this.uid = uid;
    }

@@ -401,9 +392,9 @@ class BroadcastProcessQueue {
            } else if (mCountAlarm > 0) {
                mRunnableAt = runnableAt;
            } else if (mProcessCached) {
                mRunnableAt = runnableAt + DELAY_CACHED_MILLIS;
                mRunnableAt = runnableAt + constants.DELAY_CACHED_MILLIS;
            } else {
                mRunnableAt = runnableAt + DELAY_DEFAULT_MILLIS;
                mRunnableAt = runnableAt + constants.DELAY_NORMAL_MILLIS;
            }
        } else {
            mRunnableAt = Long.MAX_VALUE;
+15 −22
Original line number Diff line number Diff line
@@ -111,9 +111,17 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
            BroadcastConstants fgConstants, BroadcastConstants bgConstants,
            BroadcastSkipPolicy skipPolicy, BroadcastHistory history) {
        super(service, handler, "modern", skipPolicy, history);

        // For the moment, read agnostic constants from foreground
        mConstants = Objects.requireNonNull(fgConstants);
        mFgConstants = Objects.requireNonNull(fgConstants);
        mBgConstants = Objects.requireNonNull(bgConstants);

        mLocalHandler = new Handler(handler.getLooper(), mLocalCallback);

        // We configure runnable size only once at boot; it'd be too complex to
        // try resizing dynamically at runtime
        mRunning = new BroadcastProcessQueue[mConstants.MAX_RUNNING_PROCESS_QUEUES];
    }

    // TODO: add support for replacing pending broadcasts
@@ -124,21 +132,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
    // TODO: pause queues when background services are running
    // TODO: pause queues when processes are frozen

    /**
     * Maximum number of process queues to dispatch broadcasts to
     * simultaneously.
     */
    // TODO: shift hard-coded defaults to BroadcastConstants
    private static final int MAX_RUNNING_PROCESS_QUEUES = 4;

    /**
     * Maximum number of active broadcasts to dispatch to a "running" process
     * queue before we retire them back to being "runnable" to give other
     * processes a chance to run.
     */
    // TODO: shift hard-coded defaults to BroadcastConstants
    private static final int MAX_RUNNING_ACTIVE_BROADCASTS = 16;

    /**
     * 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
@@ -168,8 +161,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
     * @see #getRunningIndexOf
     */
    @GuardedBy("mService")
    private final BroadcastProcessQueue[] mRunning =
            new BroadcastProcessQueue[MAX_RUNNING_PROCESS_QUEUES];
    private final BroadcastProcessQueue[] mRunning;

    /**
     * Single queue which is "running" but is awaiting a cold start to be
@@ -185,6 +177,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
    @GuardedBy("mService")
    private final ArrayList<CountDownLatch> mWaitingForIdle = new ArrayList<>();

    private final BroadcastConstants mConstants;
    private final BroadcastConstants mFgConstants;
    private final BroadcastConstants mBgConstants;

@@ -299,12 +292,12 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
     * Consider updating the list of "running" queues.
     * <p>
     * This method can promote "runnable" queues to become "running", subject to
     * a maximum of {@link #MAX_RUNNING_PROCESS_QUEUES} warm processes and only
     * one pending cold-start.
     * a maximum of {@link BroadcastConstants#MAX_RUNNING_PROCESS_QUEUES} warm
     * processes and only one pending cold-start.
     */
    @GuardedBy("mService")
    private void updateRunningList() {
        int avail = MAX_RUNNING_PROCESS_QUEUES - getRunningSize();
        int avail = mRunning.length - getRunningSize();
        if (avail == 0) return;

        final int cookie = traceBegin(TAG, "updateRunningList");
@@ -714,7 +707,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        // Even if we have more broadcasts, if we've made reasonable progress
        // and someone else is waiting, retire ourselves to avoid starvation
        final boolean shouldRetire = (mRunnableHead != null)
                && (queue.getActiveCountSinceIdle() > MAX_RUNNING_ACTIVE_BROADCASTS);
                && (queue.getActiveCountSinceIdle() > mConstants.MAX_RUNNING_ACTIVE_BROADCASTS);

        if (queue.isRunnable() && queue.isProcessWarm() && !shouldRetire) {
            // We're on a roll; move onto the next broadcast for this process
@@ -1034,7 +1027,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
            leaf = leaf.processNameNext;
        }

        BroadcastProcessQueue created = new BroadcastProcessQueue(processName, uid);
        BroadcastProcessQueue created = new BroadcastProcessQueue(mConstants, processName, uid);
        created.app = mService.getProcessRecordLocked(processName, uid);

        if (leaf == null) {
+11 −8
Original line number Diff line number Diff line
@@ -65,6 +65,8 @@ public class BroadcastQueueModernImplTest {
    @Mock BroadcastProcessQueue mQueue4;

    HandlerThread mHandlerThread;

    BroadcastConstants mConstants;
    BroadcastQueueModernImpl mImpl;

    BroadcastProcessQueue mHead;
@@ -75,9 +77,10 @@ public class BroadcastQueueModernImplTest {

        mHandlerThread = new HandlerThread(getClass().getSimpleName());
        mHandlerThread.start();

        mConstants = new BroadcastConstants(Settings.Global.BROADCAST_FG_CONSTANTS);
        mImpl = new BroadcastQueueModernImpl(mAms, mHandlerThread.getThreadHandler(),
                new BroadcastConstants(Settings.Global.BROADCAST_FG_CONSTANTS),
                new BroadcastConstants(Settings.Global.BROADCAST_BG_CONSTANTS));
                mConstants, mConstants);

        doReturn(1L).when(mQueue1).getRunnableAt();
        doReturn(2L).when(mQueue2).getRunnableAt();
@@ -240,8 +243,8 @@ public class BroadcastQueueModernImplTest {
     */
    @Test
    public void testRunnableAt_Empty() {
        BroadcastProcessQueue queue = new BroadcastProcessQueue(PACKAGE_GREEN,
                getUidForPackage(PACKAGE_GREEN));
        BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
                PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
        assertFalse(queue.isRunnable());
        assertEquals(Long.MAX_VALUE, queue.getRunnableAt());
    }
@@ -252,8 +255,8 @@ public class BroadcastQueueModernImplTest {
     */
    @Test
    public void testRunnableAt_Normal() {
        BroadcastProcessQueue queue = new BroadcastProcessQueue(PACKAGE_GREEN,
                getUidForPackage(PACKAGE_GREEN));
        BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
                PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));

        final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane);
@@ -272,8 +275,8 @@ public class BroadcastQueueModernImplTest {
     */
    @Test
    public void testRunnableAt_Foreground() {
        BroadcastProcessQueue queue = new BroadcastProcessQueue(PACKAGE_GREEN,
                getUidForPackage(PACKAGE_GREEN));
        BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
                PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));

        final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        airplane.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);