diff options
| author | 2024-12-30 05:56:55 -0800 | |
|---|---|---|
| committer | 2024-12-30 05:56:55 -0800 | |
| commit | 5e15c15179aab7f5bd9bef9f260f87320f8521a6 (patch) | |
| tree | 6ce2d5829952050f550f14c4a3e3583881b6471d | |
| parent | 2d598a12bee7ba31ea9f523b093bc9f4ae154ccf (diff) | |
| parent | a6d46200becfa6af0b11bb7df58009dc55f3fb75 (diff) | |
Merge "Stop duplicate broadcasts to registered receivers in zen-access packages" into main
3 files changed, 119 insertions, 11 deletions
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index eeae6166873a..f50e8aa7eb7b 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -3082,16 +3082,42 @@ public class NotificationManagerService extends SystemService { private void sendRegisteredOnlyBroadcast(Intent baseIntent) { int[] userIds = mUmInternal.getProfileIds(mAmi.getCurrentUserId(), true); - Intent intent = new Intent(baseIntent).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - for (int userId : userIds) { - getContext().sendBroadcastAsUser(intent, UserHandle.of(userId), null); - } - // explicitly send the broadcast to all DND packages, even if they aren't currently running - for (int userId : userIds) { - for (String pkg : mConditionProviders.getAllowedPackages(userId)) { - Intent pkgIntent = new Intent(baseIntent).setPackage(pkg).setFlags( - Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - getContext().sendBroadcastAsUser(pkgIntent, UserHandle.of(userId)); + if (Flags.nmBinderPerfReduceZenBroadcasts()) { + for (int userId : userIds) { + Context userContext = getContext().createContextAsUser(UserHandle.of(userId), 0); + String[] dndPackages = mConditionProviders.getAllowedPackages(userId) + .toArray(new String[0]); + + // We send the broadcast to all DND packages in the second step, so leave them out + // of this first broadcast for *running* receivers. That ensures each package only + // receives it once. + Intent registeredOnlyIntent = new Intent(baseIntent) + .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + userContext.sendBroadcastMultiplePermissions(registeredOnlyIntent, + /* receiverPermissions= */ new String[0], + /* excludedPermissions= */ new String[0], + /* excludedPackages= */ dndPackages); + + for (String pkg : dndPackages) { + Intent pkgIntent = new Intent(baseIntent).setPackage(pkg) + .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + userContext.sendBroadcast(pkgIntent); + } + } + } else { + Intent intent = new Intent(baseIntent).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + for (int userId : userIds) { + getContext().sendBroadcastAsUser(intent, UserHandle.of(userId), null); + } + + // explicitly send the broadcast to all DND packages, even if they aren't currently + // running + for (int userId : userIds) { + for (String pkg : mConditionProviders.getAllowedPackages(userId)) { + Intent pkgIntent = new Intent(baseIntent).setPackage(pkg).setFlags( + Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + getContext().sendBroadcastAsUser(pkgIntent, UserHandle.of(userId)); + } } } } diff --git a/services/core/java/com/android/server/notification/flags.aconfig b/services/core/java/com/android/server/notification/flags.aconfig index 65a38ae1fcde..f15c23e110a4 100644 --- a/services/core/java/com/android/server/notification/flags.aconfig +++ b/services/core/java/com/android/server/notification/flags.aconfig @@ -187,3 +187,13 @@ flag { description: "Enables sound uri with vibration source in notification channel" bug: "351975435" } + +flag { + name: "nm_binder_perf_reduce_zen_broadcasts" + namespace: "systemui" + description: "Don't send duplicate zen-related (policy changed, etc) broadcasts" + bug: "324376849" + metadata { + purpose: PURPOSE_BUGFIX + } +}
\ No newline at end of file diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index bcda2c0662ca..301165f8151d 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -644,6 +644,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { doNothing().when(mContext).sendBroadcast(any(), anyString()); doNothing().when(mContext).sendBroadcastAsUser(any(), any()); doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any()); + doNothing().when(mContext).sendBroadcastMultiplePermissions(any(), any(), any(), any()); + doReturn(mContext).when(mContext).createContextAsUser(eq(mUser), anyInt()); + TestableContentResolver cr = mock(TestableContentResolver.class); when(mContext.getContentResolver()).thenReturn(cr); doNothing().when(cr).registerContentObserver(any(), anyBoolean(), any(), anyInt()); @@ -11235,7 +11238,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - public void onZenModeChanged_sendsBroadcasts() throws Exception { + @DisableFlags(Flags.FLAG_NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS) + public void onZenModeChanged_sendsBroadcasts_oldBehavior() throws Exception { when(mAmi.getCurrentUserId()).thenReturn(100); when(mUmInternal.getProfileIds(eq(100), anyBoolean())).thenReturn(new int[]{100, 101, 102}); when(mConditionProviders.getAllowedPackages(anyInt())).then(new Answer<List<String>>() { @@ -11288,6 +11292,74 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + @EnableFlags(Flags.FLAG_NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS) + public void onZenModeChanged_sendsBroadcasts() throws Exception { + when(mAmi.getCurrentUserId()).thenReturn(100); + when(mUmInternal.getProfileIds(eq(100), anyBoolean())).thenReturn(new int[]{100, 101, 102}); + when(mConditionProviders.getAllowedPackages(anyInt())).then(new Answer<List<String>>() { + @Override + public List<String> answer(InvocationOnMock invocation) { + int userId = invocation.getArgument(0); + switch (userId) { + case 100: + return Lists.newArrayList("a", "b", "c"); + case 101: + return Lists.newArrayList(); + case 102: + return Lists.newArrayList("b"); + default: + throw new IllegalArgumentException( + "Why would you ask for packages of userId " + userId + "?"); + } + } + }); + Context context100 = mock(Context.class); + doReturn(context100).when(mContext).createContextAsUser(eq(UserHandle.of(100)), anyInt()); + Context context101 = mock(Context.class); + doReturn(context101).when(mContext).createContextAsUser(eq(UserHandle.of(101)), anyInt()); + Context context102 = mock(Context.class); + doReturn(context102).when(mContext).createContextAsUser(eq(UserHandle.of(102)), anyInt()); + + mService.getBinderService().setZenMode(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS, null, + "testing!", false); + waitForIdle(); + + // Verify broadcasts per user: registered receivers first, then DND packages. + InOrder inOrder = inOrder(context100, context101, context102); + + inOrder.verify(context100).sendBroadcastMultiplePermissions( + eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED) + .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)), + eq(new String[0]), eq(new String[0]), eq(new String[] {"a", "b", "c"})); + inOrder.verify(context100).sendBroadcast( + eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED) + .setPackage("a") + .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT))); + inOrder.verify(context100).sendBroadcast( + eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED) + .setPackage("b") + .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT))); + inOrder.verify(context100).sendBroadcast( + eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED) + .setPackage("c") + .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT))); + + inOrder.verify(context101).sendBroadcastMultiplePermissions( + eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED) + .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)), + eq(new String[0]), eq(new String[0]), eq(new String[] {})); + + inOrder.verify(context102).sendBroadcastMultiplePermissions( + eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED) + .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)), + eq(new String[0]), eq(new String[0]), eq(new String[] {"b"})); + inOrder.verify(context102).sendBroadcast( + eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED) + .setPackage("b") + .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT))); + } + + @Test @EnableFlags(android.app.Flags.FLAG_MODES_API) public void onAutomaticRuleStatusChanged_sendsBroadcastToRuleOwner() throws Exception { mService.mZenModeHelper.getCallbacks().forEach(c -> c.onAutomaticRuleStatusChanged( |