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

Commit 0d58af73 authored by Yuri Lin's avatar Yuri Lin
Browse files

Add method to return all packages with any channels.

Used for Settings, where before this (and attached) change was generating the list of apps with any channels by calling getNumNotificationChannelsForPackage for each app in sequence. This reduces many binder calls to one per user.

Bug: 394614704
Test: PreferencesHelperTest
Flag: android.app.nm_binder_perf_get_apps_with_channels
Change-Id: Ieb40e378682a9f2950c4a3eb6c2a8637323e82b6
parent ef74fc97
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -125,6 +125,7 @@ interface INotificationManager
    boolean areChannelsBypassingDnd();
    ParceledListSlice getNotificationChannelsBypassingDnd(String pkg, int uid);
    ParceledListSlice getPackagesBypassingDnd(int userId);
    List<String> getPackagesWithAnyChannels(int userId);
    boolean isPackagePaused(String pkg);
    void deleteNotificationHistoryItem(String pkg, int uid, long postedTime);
    boolean isPermissionFixed(String pkg, int userId);
+10 −0
Original line number Diff line number Diff line
@@ -297,6 +297,16 @@ flag {
  }
}

flag {
  name: "nm_binder_perf_get_apps_with_channels"
  namespace: "systemui"
  description: "Use a single binder call to get the set of apps with channels for a user"
  bug: "362981561"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}

flag {
  name: "no_sbnholder"
  namespace: "systemui"
+15 −0
Original line number Diff line number Diff line
@@ -5233,6 +5233,21 @@ public class NotificationManagerService extends SystemService {
            return mPreferencesHelper.areChannelsBypassingDnd();
        }
        @Override
        @FlaggedApi(android.app.Flags.FLAG_NM_BINDER_PERF_GET_APPS_WITH_CHANNELS)
        public List<String> getPackagesWithAnyChannels(int userId) throws RemoteException {
            checkCallerIsSystem();
            UserHandle user = UserHandle.of(userId);
            List<String> packages = mPreferencesHelper.getPackagesWithAnyChannels(userId);
            for (int i = packages.size() - 1; i >= 0; i--) {
                String pkg = packages.get(i);
                if (!areNotificationsEnabledForPackage(pkg, getUidForPackageAndUser(pkg, user))) {
                    packages.remove(i);
                }
            }
            return packages;
        }
        @Override
        public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
            boolean packagesChanged = false;
+23 −0
Original line number Diff line number Diff line
@@ -1987,6 +1987,29 @@ public class PreferencesHelper implements RankingConfig {
        return bypassing;
    }

    /**
     * Gets all apps for this user that have a nonzero number of channels. This count does not
     * include deleted channels.
     */
    @FlaggedApi(android.app.Flags.FLAG_NM_BINDER_PERF_GET_APPS_WITH_CHANNELS)
    public @NonNull List<String> getPackagesWithAnyChannels(@UserIdInt int userId) {
        List<String> pkgs = new ArrayList<>();
        synchronized (mLock) {
            for (PackagePreferences p : mPackagePreferences.values()) {
                if (UserHandle.getUserId(p.uid) != userId) {
                    continue;
                }
                for (NotificationChannel c : p.channels.values()) {
                    if (!c.isDeleted()) {
                        pkgs.add(p.pkg);
                        break;
                    }
                }
            }
        }
        return pkgs;
    }

    /**
     * True for pre-O apps that only have the default channel, or pre O apps that have no
     * channels yet. This method will create the default channel for pre-O apps that don't have it.
+36 −1
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.NOT_
import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.SHOW_IMMEDIATELY;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.Flags.FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS;
import static android.app.Flags.FLAG_NM_BINDER_PERF_CACHE_CHANNELS;
import static android.app.Flags.FLAG_SORT_SECTION_BY_TIME;
import static android.app.Notification.EXTRA_ALLOW_DURING_SETUP;
import static android.app.Notification.EXTRA_PICTURE;
@@ -5379,6 +5378,42 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        verify(mPreferencesHelper, never()).getNotificationChannelGroups(anyString(), anyInt());
    }
    @Test
    public void testGetPackagesWithChannels_blocked() throws Exception {
        // While we mostly rely on the PreferencesHelper implementation of channels, we filter in
        // NMS so that we do not return blocked packages.
        // Three packages; all under user 1.
        // pkg2 is blocked, but pkg1 and pkg3 are not.
        String pkg1 = "com.package.one", pkg2 = "com.package.two", pkg3 = "com.package.three";
        int uid1 = UserHandle.getUid(1, 111);
        int uid2 = UserHandle.getUid(1, 222);
        int uid3 = UserHandle.getUid(1, 333);
        when(mPackageManager.getPackageUid(eq(pkg1), anyLong(), anyInt())).thenReturn(uid1);
        when(mPackageManager.getPackageUid(eq(pkg2), anyLong(), anyInt())).thenReturn(uid2);
        when(mPackageManager.getPackageUid(eq(pkg3), anyLong(), anyInt())).thenReturn(uid3);
        when(mPermissionHelper.hasPermission(uid1)).thenReturn(true);
        when(mPermissionHelper.hasPermission(uid2)).thenReturn(false);
        when(mPermissionHelper.hasPermission(uid3)).thenReturn(true);
        NotificationChannel channel1 = new NotificationChannel("id1", "name1",
                NotificationManager.IMPORTANCE_DEFAULT);
        NotificationChannel channel2 = new NotificationChannel("id3", "name3",
                NotificationManager.IMPORTANCE_DEFAULT);
        NotificationChannel channel3 = new NotificationChannel("id4", "name3",
                NotificationManager.IMPORTANCE_DEFAULT);
        mService.mPreferencesHelper.createNotificationChannel(pkg1, uid1, channel1, true, false,
                uid1, false);
        mService.mPreferencesHelper.createNotificationChannel(pkg2, uid2, channel2, true, false,
                uid2, false);
        mService.mPreferencesHelper.createNotificationChannel(pkg3, uid3, channel3, true, false,
                uid3, false);
        // Output should contain only the package with notification permissions (1, 3).
        enableInteractAcrossUsers();
        assertThat(mBinderService.getPackagesWithAnyChannels(1)).containsExactly(pkg1, pkg3);
    }
    @Test
    public void testHasCompanionDevice_failure() throws Exception {
        when(mCompanionMgr.getAssociations(anyString(), anyInt())).thenThrow(
Loading