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

Commit a6d46200 authored by Matías Hernández's avatar Matías Hernández
Browse files

Stop duplicate broadcasts to registered receivers in zen-access packages

Bug: 324376849
Test: atest NotificationManagerServiceTest + CTS
Flag: com.android.server.notification.nm_binder_perf_reduce_zen_broadcasts
Change-Id: Iefd04e7e28b99f5fe8898b8ab2415e5181908307
parent ba2ddbe8
Loading
Loading
Loading
Loading
+36 −10
Original line number Diff line number Diff line
@@ -3082,11 +3082,36 @@ public class NotificationManagerService extends SystemService {
    private void sendRegisteredOnlyBroadcast(Intent baseIntent) {
        int[] userIds = mUmInternal.getProfileIds(mAmi.getCurrentUserId(), true);
        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
            // 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(
@@ -3095,6 +3120,7 @@ public class NotificationManagerService extends SystemService {
                }
            }
        }
    }
    @Override
    public void onBootPhase(int phase) {
+10 −0
Original line number Diff line number Diff line
@@ -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
+76 −4
Original line number Diff line number Diff line
@@ -365,6 +365,9 @@ import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
import platform.test.runner.parameterized.Parameters;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
@@ -380,9 +383,6 @@ import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer;
import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
import platform.test.runner.parameterized.Parameters;
@SmallTest
@RunWith(ParameterizedAndroidJunit4.class)
@RunWithLooper
@@ -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>>() {
@@ -11287,6 +11291,74 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(102)));
    }
    @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 {