diff options
4 files changed, 87 insertions, 50 deletions
diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java index 2ebe0b48296b..3efb628a8b75 100644 --- a/services/core/java/com/android/server/am/BroadcastConstants.java +++ b/services/core/java/com/android/server/am/BroadcastConstants.java @@ -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 */ diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java index 38f71e1dd18a..70fb7a3e962b 100644 --- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java +++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java @@ -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; diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index 761e12c52263..d60ad991d91e 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -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 @@ -125,21 +133,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue { // 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 * {@link BroadcastProcessQueue#next}. @@ -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) { diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java index 00e11a327d91..2b1f4a3ce56c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java @@ -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); |