diff options
13 files changed, 187 insertions, 33 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index 1d93eb3a211a..e38e21febbf1 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -2625,7 +2625,7 @@ public class DeviceIdleController extends SystemService final Bundle mostRecentDeliveryOptions = BroadcastOptions.makeBasic() .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) - .setDeferUntilActive(true) + .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) .toBundle(); mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java index 1151bb7d0e6a..394be6ef11ca 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java @@ -1948,7 +1948,7 @@ public class AlarmManagerService extends SystemService { | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); mTimeTickOptions = BroadcastOptions.makeBasic() .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) - .setDeferUntilActive(true) + .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) .toBundle(); mTimeTickTrigger = new IAlarmListener.Stub() { @Override diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index e9a7f205c519..d94f4f22f2c9 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -194,19 +194,19 @@ public final class BatteryService extends SystemService { private Bundle mBatteryChangedOptions = BroadcastOptions.makeBasic() .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) - .setDeferUntilActive(true) + .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) .toBundle(); /** Used for both connected/disconnected, so match using key */ private Bundle mPowerOptions = BroadcastOptions.makeBasic() .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) .setDeliveryGroupMatchingKey("android", Intent.ACTION_POWER_CONNECTED) - .setDeferUntilActive(true) + .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) .toBundle(); /** Used for both low/okay, so match using key */ private Bundle mBatteryOptions = BroadcastOptions.makeBasic() .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) .setDeliveryGroupMatchingKey("android", Intent.ACTION_BATTERY_OKAY) - .setDeferUntilActive(true) + .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) .toBundle(); private MetricsLogger mMetricsLogger; diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java index 19e5cb142cfd..a3dc21e70281 100644 --- a/services/core/java/com/android/server/DropBoxManagerService.java +++ b/services/core/java/com/android/server/DropBoxManagerService.java @@ -320,7 +320,7 @@ public final class DropBoxManagerService extends SystemService { .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MERGED) .setDeliveryGroupMatchingFilter(matchingFilter) .setDeliveryGroupExtrasMerger(extrasMerger) - .setDeferUntilActive(true) + .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) .toBundle(); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index c74aa7f1fc49..8ae955029138 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -14507,18 +14507,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - // resultTo broadcasts are always infinitely deferrable. - if ((resultTo != null) && !ordered && mEnableModernQueue) { - if (brOptions == null) { - brOptions = BroadcastOptions.makeBasic(); - } - brOptions.setDeferUntilActive(true); - } - - if (mEnableModernQueue && ordered && brOptions != null && brOptions.isDeferUntilActive()) { - throw new IllegalArgumentException("Ordered broadcasts can't be deferred until active"); - } - // Verify that protected broadcasts are only being sent by system code, // and that system code is only sending protected broadcasts. final boolean isProtectedBroadcast; diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java index 53fcddf215c6..33d4004a9027 100644 --- a/services/core/java/com/android/server/am/BroadcastConstants.java +++ b/services/core/java/com/android/server/am/BroadcastConstants.java @@ -236,6 +236,14 @@ public class BroadcastConstants { private static final int DEFAULT_MAX_HISTORY_SUMMARY_SIZE = ActivityManager.isLowRamDeviceStatic() ? 256 : 1024; + /** + * For {@link BroadcastRecord}: Default to treating all broadcasts sent by + * the system as be {@link BroadcastOptions#DEFERRAL_POLICY_UNTIL_ACTIVE}. + */ + public boolean CORE_DEFER_UNTIL_ACTIVE = DEFAULT_CORE_DEFER_UNTIL_ACTIVE; + private static final String KEY_CORE_DEFER_UNTIL_ACTIVE = "bcast_core_defer_until_active"; + private static final boolean DEFAULT_CORE_DEFER_UNTIL_ACTIVE = false; + // Settings override tracking for this instance private String mSettingsKey; private SettingsObserver mSettingsObserver; @@ -373,7 +381,12 @@ public class BroadcastConstants { DEFAULT_MAX_HISTORY_COMPLETE_SIZE); MAX_HISTORY_SUMMARY_SIZE = getDeviceConfigInt(KEY_MAX_HISTORY_SUMMARY_SIZE, DEFAULT_MAX_HISTORY_SUMMARY_SIZE); + CORE_DEFER_UNTIL_ACTIVE = getDeviceConfigBoolean(KEY_CORE_DEFER_UNTIL_ACTIVE, + DEFAULT_CORE_DEFER_UNTIL_ACTIVE); } + + // TODO: migrate BroadcastRecord to accept a BroadcastConstants + BroadcastRecord.CORE_DEFER_UNTIL_ACTIVE = CORE_DEFER_UNTIL_ACTIVE; } /** @@ -418,6 +431,8 @@ public class BroadcastConstants { MAX_CONSECUTIVE_URGENT_DISPATCHES).println(); pw.print(KEY_MAX_CONSECUTIVE_NORMAL_DISPATCHES, MAX_CONSECUTIVE_NORMAL_DISPATCHES).println(); + pw.print(KEY_CORE_DEFER_UNTIL_ACTIVE, + CORE_DEFER_UNTIL_ACTIVE).println(); pw.decreaseIndent(); pw.println(); } diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java index 59f33ddb795d..6bd3c7953e01 100644 --- a/services/core/java/com/android/server/am/BroadcastRecord.java +++ b/services/core/java/com/android/server/am/BroadcastRecord.java @@ -90,6 +90,7 @@ final class BroadcastRecord extends Binder { final boolean prioritized; // contains more than one priority tranche final boolean deferUntilActive; // infinitely deferrable broadcast final boolean shareIdentity; // whether the broadcaster's identity should be shared + final boolean urgent; // has been classified as "urgent" final int userId; // user id this broadcast was for final @Nullable String resolvedType; // the resolved data type final @Nullable String[] requiredPermissions; // permissions the caller has required @@ -146,6 +147,13 @@ final class BroadcastRecord extends Binder { private @Nullable String mCachedToString; private @Nullable String mCachedToShortString; + /** + * When enabled, assume that {@link UserHandle#isCore(int)} apps should + * treat {@link BroadcastOptions#DEFERRAL_POLICY_DEFAULT} as + * {@link BroadcastOptions#DEFERRAL_POLICY_UNTIL_ACTIVE}. + */ + static boolean CORE_DEFER_UNTIL_ACTIVE = false; + /** Empty immutable list of receivers */ static final List<Object> EMPTY_RECEIVERS = List.of(); @@ -400,7 +408,9 @@ final class BroadcastRecord extends Binder { receivers = (_receivers != null) ? _receivers : EMPTY_RECEIVERS; delivery = new int[_receivers != null ? _receivers.size() : 0]; deliveryReasons = new String[delivery.length]; - deferUntilActive = options != null ? options.isDeferUntilActive() : false; + urgent = calculateUrgent(_intent, _options); + deferUntilActive = calculateDeferUntilActive(_callingUid, + _options, _resultTo, _serialized, urgent); deferredUntilActive = new boolean[deferUntilActive ? delivery.length : 0]; blockedUntilTerminalCount = calculateBlockedUntilTerminalCount(receivers, _serialized); scheduledTime = new long[delivery.length]; @@ -488,6 +498,7 @@ final class BroadcastRecord extends Binder { pushMessageOverQuota = from.pushMessageOverQuota; interactive = from.interactive; shareIdentity = from.shareIdentity; + urgent = from.urgent; filterExtrasForReceiver = from.filterExtrasForReceiver; } @@ -681,15 +692,8 @@ final class BroadcastRecord extends Binder { return deferUntilActive; } - /** - * Core policy determination about this broadcast's delivery prioritization - */ boolean isUrgent() { - // TODO: flags for controlling policy - // TODO: migrate alarm-prioritization flag to BroadcastConstants - return (isForeground() - || interactive - || alarm); + return urgent; } @NonNull String getHostingRecordTriggerType() { @@ -849,6 +853,69 @@ final class BroadcastRecord extends Binder { } } + /** + * Core policy determination about this broadcast's delivery prioritization + */ + @VisibleForTesting + static boolean calculateUrgent(@NonNull Intent intent, @Nullable BroadcastOptions options) { + // TODO: flags for controlling policy + // TODO: migrate alarm-prioritization flag to BroadcastConstants + if ((intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0) { + return true; + } + if (options != null) { + if (options.isInteractive()) { + return true; + } + if (options.isAlarmBroadcast()) { + return true; + } + } + return false; + } + + /** + * Resolve the requested {@link BroadcastOptions#setDeferralPolicy(int)} + * against this broadcast state to determine if it should be marked as + * "defer until active". + */ + @VisibleForTesting + static boolean calculateDeferUntilActive(int callingUid, @Nullable BroadcastOptions options, + @Nullable IIntentReceiver resultTo, boolean ordered, boolean urgent) { + // Ordered broadcasts can never be deferred until active + if (ordered) { + return false; + } + + // Unordered resultTo broadcasts are always deferred until active + if (!ordered && resultTo != null) { + return true; + } + + // Determine if a strong preference in either direction was expressed; + // a preference here overrides all remaining policies + if (options != null) { + switch (options.getDeferralPolicy()) { + case BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE: + return true; + case BroadcastOptions.DEFERRAL_POLICY_NONE: + return false; + } + } + + // Urgent broadcasts aren't deferred until active + if (urgent) { + return false; + } + + // Otherwise, choose a reasonable default + if (CORE_DEFER_UNTIL_ACTIVE && UserHandle.isCore(callingUid)) { + return true; + } else { + return false; + } + } + public BroadcastRecord maybeStripForHistory() { if (!intent.canStripForHistory()) { return this; diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 490a33eee4e6..e403861f80ee 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -8170,7 +8170,7 @@ public class AudioService extends IAudioService.Stub volumeChangedOptions.setDeliveryGroupPolicy(DELIVERY_GROUP_POLICY_MOST_RECENT); volumeChangedOptions.setDeliveryGroupMatchingKey( AudioManager.VOLUME_CHANGED_ACTION, String.valueOf(mStreamType)); - volumeChangedOptions.setDeferUntilActive(true); + volumeChangedOptions.setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE); mVolumeChangedOptions = volumeChangedOptions.toBundle(); mStreamDevicesChanged = new Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION); @@ -8179,7 +8179,8 @@ public class AudioService extends IAudioService.Stub streamDevicesChangedOptions.setDeliveryGroupPolicy(DELIVERY_GROUP_POLICY_MOST_RECENT); streamDevicesChangedOptions.setDeliveryGroupMatchingKey( AudioManager.STREAM_DEVICES_CHANGED_ACTION, String.valueOf(mStreamType)); - streamDevicesChangedOptions.setDeferUntilActive(true); + streamDevicesChangedOptions.setDeferralPolicy( + BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE); mStreamDevicesChangedOptions = streamDevicesChangedOptions.toBundle(); } diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java index 3e2efdd7db85..20ff51c22783 100644 --- a/services/core/java/com/android/server/dreams/DreamController.java +++ b/services/core/java/com/android/server/dreams/DreamController.java @@ -120,7 +120,7 @@ final class DreamController { options.setDeliveryGroupMatchingKey( DREAMING_DELIVERY_GROUP_NAMESPACE, DREAMING_DELIVERY_GROUP_KEY); // This allows the broadcast delivery to be delayed to apps in the Cached state. - options.setDeferUntilActive(true); + options.setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE); return options.toBundle(); } diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index da7aaa4fd478..d0ed9bfbb285 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -241,7 +241,7 @@ public class Notifier { UUID.randomUUID().toString(), Intent.ACTION_SCREEN_ON); // This allows the broadcast delivery to be delayed to apps in the Cached state. - options.setDeferUntilActive(true); + options.setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE); return options.toBundle(); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 6cd9f1c3f9a0..a1789b2b125d 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -3224,7 +3224,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); Bundle options = new BroadcastOptions() .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) - .setDeferUntilActive(true) + .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) .toBundle(); mInjector.binderWithCleanCallingIdentity(() -> mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle), null, options)); diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java index b395f42478b1..e7e26a1268e0 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java @@ -1303,7 +1303,8 @@ public final class AlarmManagerServiceTest { final BroadcastOptions actualOptions = new BroadcastOptions(actualOptionsBundle); assertEquals(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT, actualOptions.getDeliveryGroupPolicy()); - assertTrue(actualOptions.isDeferUntilActive()); + assertEquals(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE, + actualOptions.getDeferralPolicy()); } @Test diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java index 01e27684aaf7..2b6f2174d49b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java @@ -25,6 +25,8 @@ import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROA import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_BACKGROUND_RESTRICTED_ONLY; import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_NONE; import static com.android.server.am.BroadcastRecord.calculateBlockedUntilTerminalCount; +import static com.android.server.am.BroadcastRecord.calculateDeferUntilActive; +import static com.android.server.am.BroadcastRecord.calculateUrgent; import static com.android.server.am.BroadcastRecord.isReceiverEquals; import static org.junit.Assert.assertArrayEquals; @@ -38,6 +40,7 @@ import static org.mockito.Mockito.doReturn; import android.app.ActivityManagerInternal; import android.app.BackgroundStartPrivileges; import android.app.BroadcastOptions; +import android.content.IIntentReceiver; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; @@ -55,6 +58,7 @@ import androidx.test.filters.SmallTest; import com.android.server.am.BroadcastDispatcher.DeferredBootCompletedBroadcastPerUser; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -86,6 +90,15 @@ public class BroadcastRecordTest { private static final String[] PACKAGE_LIST = new String[] {PACKAGE1, PACKAGE2, PACKAGE3, PACKAGE4}; + private static final int SYSTEM_UID = android.os.Process.SYSTEM_UID; + private static final int APP_UID = android.os.Process.FIRST_APPLICATION_UID; + + private static final BroadcastOptions OPT_DEFAULT = BroadcastOptions.makeBasic(); + private static final BroadcastOptions OPT_NONE = BroadcastOptions.makeBasic() + .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_NONE); + private static final BroadcastOptions OPT_UNTIL_ACTIVE = BroadcastOptions.makeBasic() + .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE); + @Mock ActivityManagerInternal mActivityManagerInternal; @Mock BroadcastQueue mQueue; @Mock ProcessRecord mProcess; @@ -213,6 +226,75 @@ public class BroadcastRecordTest { } @Test + public void testCalculateUrgent() { + final Intent intent = new Intent(); + final Intent intentForeground = new Intent() + .setFlags(Intent.FLAG_RECEIVER_FOREGROUND); + + assertFalse(calculateUrgent(intent, null)); + assertTrue(calculateUrgent(intentForeground, null)); + + { + final BroadcastOptions opts = BroadcastOptions.makeBasic(); + assertFalse(calculateUrgent(intent, opts)); + } + { + final BroadcastOptions opts = BroadcastOptions.makeBasic(); + opts.setInteractive(true); + assertTrue(calculateUrgent(intent, opts)); + } + { + final BroadcastOptions opts = BroadcastOptions.makeBasic(); + opts.setAlarmBroadcast(true); + assertTrue(calculateUrgent(intent, opts)); + } + } + + @Test + public void testCalculateDeferUntilActive_App() { + // Verify non-urgent behavior + assertFalse(calculateDeferUntilActive(APP_UID, null, null, false, false)); + assertFalse(calculateDeferUntilActive(APP_UID, OPT_DEFAULT, null, false, false)); + assertFalse(calculateDeferUntilActive(APP_UID, OPT_NONE, null, false, false)); + assertTrue(calculateDeferUntilActive(APP_UID, OPT_UNTIL_ACTIVE, null, false, false)); + + // Verify urgent behavior + assertFalse(calculateDeferUntilActive(APP_UID, null, null, false, true)); + assertFalse(calculateDeferUntilActive(APP_UID, OPT_DEFAULT, null, false, true)); + assertFalse(calculateDeferUntilActive(APP_UID, OPT_NONE, null, false, true)); + assertTrue(calculateDeferUntilActive(APP_UID, OPT_UNTIL_ACTIVE, null, false, true)); + } + + @Test + public void testCalculateDeferUntilActive_System() { + BroadcastRecord.CORE_DEFER_UNTIL_ACTIVE = true; + + // Verify non-urgent behavior + assertTrue(calculateDeferUntilActive(SYSTEM_UID, null, null, false, false)); + assertTrue(calculateDeferUntilActive(SYSTEM_UID, OPT_DEFAULT, null, false, false)); + assertFalse(calculateDeferUntilActive(SYSTEM_UID, OPT_NONE, null, false, false)); + assertTrue(calculateDeferUntilActive(SYSTEM_UID, OPT_UNTIL_ACTIVE, null, false, false)); + + // Verify urgent behavior + assertFalse(calculateDeferUntilActive(SYSTEM_UID, null, null, false, true)); + assertFalse(calculateDeferUntilActive(SYSTEM_UID, OPT_DEFAULT, null, false, true)); + assertFalse(calculateDeferUntilActive(SYSTEM_UID, OPT_NONE, null, false, true)); + assertTrue(calculateDeferUntilActive(SYSTEM_UID, OPT_UNTIL_ACTIVE, null, false, true)); + } + + @Test + public void testCalculateDeferUntilActive_Overrides() { + final IIntentReceiver resultTo = new IIntentReceiver.Default(); + + // Ordered broadcasts never deferred; requested option is ignored + assertFalse(calculateDeferUntilActive(APP_UID, OPT_UNTIL_ACTIVE, null, true, false)); + assertFalse(calculateDeferUntilActive(APP_UID, OPT_UNTIL_ACTIVE, resultTo, true, false)); + + // Unordered with result is always deferred; requested option is ignored + assertTrue(calculateDeferUntilActive(APP_UID, OPT_NONE, resultTo, false, false)); + } + + @Test public void testCleanupDisabledPackageReceivers() { final int user0 = UserHandle.USER_SYSTEM; final int user1 = user0 + 1; |