Loading services/core/java/com/android/server/notification/RankingHelper.java +83 −2 Original line number Diff line number Diff line Loading @@ -29,18 +29,23 @@ import android.app.NotificationChannelGroup; import android.app.NotificationManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ParceledListSlice; import android.content.pm.Signature; import android.content.res.Resources; import android.metrics.LogMaker; import android.os.Build; import android.os.UserHandle; import android.print.PrintManager; import android.provider.Settings.Secure; import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.RankingHelperProto; import android.service.notification.RankingHelperProto.RecordProto; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Pair; import android.util.Slog; import android.util.SparseBooleanArray; import android.util.proto.ProtoOutputStream; Loading Loading @@ -95,12 +100,18 @@ public class RankingHelper implements RankingConfig { private final ArrayMap<String, Record> mRecords = new ArrayMap<>(); // pkg|uid => Record private final ArrayMap<String, NotificationRecord> mProxyByGroupTmp = new ArrayMap<>(); private final ArrayMap<String, Record> mRestoredWithoutUids = new ArrayMap<>(); // pkg => Record private final ArrayMap<Pair<String, Integer>, Boolean> mSystemAppCache = new ArrayMap<>(); private final Context mContext; private final RankingHandler mRankingHandler; private final PackageManager mPm; private SparseBooleanArray mBadgingEnabled; private Signature[] mSystemSignature; private String mPermissionControllerPackageName; private String mServicesSystemSharedLibPackageName; private String mSharedSystemSharedLibPackageName; public RankingHelper(Context context, PackageManager pm, RankingHandler rankingHandler, ZenModeHelper zenHelper, NotificationUsageStats usageStats, String[] extractorNames) { mContext = context; Loading Loading @@ -130,6 +141,8 @@ public class RankingHelper implements RankingConfig { Slog.w(TAG, "Problem accessing extractor " + extractorNames[i] + ".", e); } } getSignatures(); } @SuppressWarnings("unchecked") Loading Loading @@ -571,7 +584,7 @@ public class RankingHelper implements RankingConfig { if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channel.getId())) { throw new IllegalArgumentException("Reserved id"); } final boolean isSystemApp = isSystemPackage(pkg, uid); NotificationChannel existing = r.channels.get(channel.getId()); // Keep most of the existing settings if (existing != null && fromTargetApp) { Loading @@ -597,6 +610,11 @@ public class RankingHelper implements RankingConfig { existing.setImportance(channel.getImportance()); } // system apps can bypass dnd if the user hasn't changed any fields on the channel yet if (existing.getUserLockedFields() == 0 & isSystemApp) { existing.setBypassDnd(channel.canBypassDnd()); } updateConfig(); return; } Loading @@ -604,9 +622,12 @@ public class RankingHelper implements RankingConfig { || channel.getImportance() > NotificationManager.IMPORTANCE_MAX) { throw new IllegalArgumentException("Invalid importance level"); } // Reset fields that apps aren't allowed to set. if (fromTargetApp) { if (fromTargetApp && !isSystemApp) { channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX); } if (fromTargetApp) { channel.setLockscreenVisibility(r.visibility); } clearLockedFields(channel); Loading @@ -616,6 +637,7 @@ public class RankingHelper implements RankingConfig { if (!r.showBadge) { channel.setShowBadge(false); } r.channels.put(channel.getId(), channel); MetricsLogger.action(getChannelLog(channel, pkg).setType( MetricsProto.MetricsEvent.TYPE_OPEN)); Loading @@ -625,6 +647,65 @@ public class RankingHelper implements RankingConfig { channel.unlockFields(channel.getUserLockedFields()); } /** * Determine whether a package is a "system package", in which case certain things (like * bypassing DND) should be allowed. */ private boolean isSystemPackage(String pkg, int uid) { Pair<String, Integer> app = new Pair(pkg, uid); if (mSystemAppCache.containsKey(app)) { return mSystemAppCache.get(app); } PackageInfo pi; try { pi = mPm.getPackageInfoAsUser( pkg, PackageManager.GET_SIGNATURES, UserHandle.getUserId(uid)); } catch (NameNotFoundException e) { Slog.w(TAG, "Can't find pkg", e); return false; } boolean isSystem = (mSystemSignature[0] != null && mSystemSignature[0].equals(getFirstSignature(pi))) || pkg.equals(mPermissionControllerPackageName) || pkg.equals(mServicesSystemSharedLibPackageName) || pkg.equals(mSharedSystemSharedLibPackageName) || pkg.equals(PrintManager.PRINT_SPOOLER_PACKAGE_NAME) || isDeviceProvisioningPackage(pkg); mSystemAppCache.put(app, isSystem); return isSystem; } private Signature getFirstSignature(PackageInfo pkg) { if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) { return pkg.signatures[0]; } return null; } private Signature getSystemSignature() { try { final PackageInfo sys = mPm.getPackageInfoAsUser( "android", PackageManager.GET_SIGNATURES, UserHandle.USER_SYSTEM); return getFirstSignature(sys); } catch (NameNotFoundException e) { } return null; } private boolean isDeviceProvisioningPackage(String packageName) { String deviceProvisioningPackage = mContext.getResources().getString( com.android.internal.R.string.config_deviceProvisioningPackage); return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName); } private void getSignatures() { mSystemSignature = new Signature[]{getSystemSignature()}; mPermissionControllerPackageName = mPm.getPermissionControllerPackageName(); mServicesSystemSharedLibPackageName = mPm.getServicesSystemSharedLibraryPackageName(); mSharedSystemSharedLibPackageName = mPm.getSharedSystemSharedLibraryPackageName(); } @Override public void updateNotificationChannel(String pkg, int uid, NotificationChannel updatedChannel, boolean fromUser) { Loading services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java +59 −0 Original line number Diff line number Diff line Loading @@ -47,7 +47,9 @@ import android.content.ContentProvider; import android.content.Context; import android.content.IContentProvider; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.Signature; import android.content.res.Resources; import android.graphics.Color; import android.media.AudioAttributes; Loading Loading @@ -97,6 +99,8 @@ public class RankingHelperTest extends UiServiceTestCase { private static final UserHandle USER = UserHandle.of(0); private static final String UPDATED_PKG = "updatedPkg"; private static final int UID2 = 1111; private static final String SYSTEM_PKG = "android"; private static final int SYSTEM_UID= 1000; private static final UserHandle USER2 = UserHandle.of(10); private static final String TEST_CHANNEL_ID = "test_channel_id"; private static final String TEST_AUTHORITY = "test"; Loading Loading @@ -136,8 +140,15 @@ public class RankingHelperTest extends UiServiceTestCase { upgrade.targetSdkVersion = Build.VERSION_CODES.O; when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy); when(mPm.getApplicationInfoAsUser(eq(UPDATED_PKG), anyInt(), anyInt())).thenReturn(upgrade); when(mPm.getApplicationInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(upgrade); when(mPm.getPackageUidAsUser(eq(PKG), anyInt())).thenReturn(UID); when(mPm.getPackageUidAsUser(eq(UPDATED_PKG), anyInt())).thenReturn(UID2); when(mPm.getPackageUidAsUser(eq(SYSTEM_PKG), anyInt())).thenReturn(SYSTEM_UID); PackageInfo info = mock(PackageInfo.class); info.signatures = new Signature[] {mock(Signature.class)}; when(mPm.getPackageInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(info); when(mPm.getPackageInfoAsUser(eq(PKG), anyInt(), anyInt())) .thenReturn(mock(PackageInfo.class)); when(mContext.getResources()).thenReturn( InstrumentationRegistry.getContext().getResources()); when(mContext.getContentResolver()).thenReturn( Loading Loading @@ -1627,4 +1638,52 @@ public class RankingHelperTest extends UiServiceTestCase { assertEquals(1, retrieved.getChannels().size()); compareChannels(a, findChannel(retrieved.getChannels(), a.getId())); } @Test public void testAndroidPkgCanBypassDnd_creation() { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); test.setBypassDnd(true); mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true); assertTrue(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false) .canBypassDnd()); } @Test public void testNormalPkgCannotBypassDnd_creation() { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); test.setBypassDnd(true); mHelper.createNotificationChannel(PKG, 1000, test, true); assertFalse(mHelper.getNotificationChannel(PKG, 1000, "A", false).canBypassDnd()); } @Test public void testAndroidPkgCanBypassDnd_update() throws Exception { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true); NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); update.setBypassDnd(true); mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, update, true); assertTrue(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false) .canBypassDnd()); // setup + 1st check verify(mPm, times(2)).getPackageInfoAsUser(any(), anyInt(), anyInt()); } @Test public void testNormalPkgCannotBypassDnd_update() { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); mHelper.createNotificationChannel(PKG, 1000, test, true); NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); update.setBypassDnd(true); mHelper.createNotificationChannel(PKG, 1000, update, true); assertFalse(mHelper.getNotificationChannel(PKG, 1000, "A", false).canBypassDnd()); } } Loading
services/core/java/com/android/server/notification/RankingHelper.java +83 −2 Original line number Diff line number Diff line Loading @@ -29,18 +29,23 @@ import android.app.NotificationChannelGroup; import android.app.NotificationManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ParceledListSlice; import android.content.pm.Signature; import android.content.res.Resources; import android.metrics.LogMaker; import android.os.Build; import android.os.UserHandle; import android.print.PrintManager; import android.provider.Settings.Secure; import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.RankingHelperProto; import android.service.notification.RankingHelperProto.RecordProto; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Pair; import android.util.Slog; import android.util.SparseBooleanArray; import android.util.proto.ProtoOutputStream; Loading Loading @@ -95,12 +100,18 @@ public class RankingHelper implements RankingConfig { private final ArrayMap<String, Record> mRecords = new ArrayMap<>(); // pkg|uid => Record private final ArrayMap<String, NotificationRecord> mProxyByGroupTmp = new ArrayMap<>(); private final ArrayMap<String, Record> mRestoredWithoutUids = new ArrayMap<>(); // pkg => Record private final ArrayMap<Pair<String, Integer>, Boolean> mSystemAppCache = new ArrayMap<>(); private final Context mContext; private final RankingHandler mRankingHandler; private final PackageManager mPm; private SparseBooleanArray mBadgingEnabled; private Signature[] mSystemSignature; private String mPermissionControllerPackageName; private String mServicesSystemSharedLibPackageName; private String mSharedSystemSharedLibPackageName; public RankingHelper(Context context, PackageManager pm, RankingHandler rankingHandler, ZenModeHelper zenHelper, NotificationUsageStats usageStats, String[] extractorNames) { mContext = context; Loading Loading @@ -130,6 +141,8 @@ public class RankingHelper implements RankingConfig { Slog.w(TAG, "Problem accessing extractor " + extractorNames[i] + ".", e); } } getSignatures(); } @SuppressWarnings("unchecked") Loading Loading @@ -571,7 +584,7 @@ public class RankingHelper implements RankingConfig { if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channel.getId())) { throw new IllegalArgumentException("Reserved id"); } final boolean isSystemApp = isSystemPackage(pkg, uid); NotificationChannel existing = r.channels.get(channel.getId()); // Keep most of the existing settings if (existing != null && fromTargetApp) { Loading @@ -597,6 +610,11 @@ public class RankingHelper implements RankingConfig { existing.setImportance(channel.getImportance()); } // system apps can bypass dnd if the user hasn't changed any fields on the channel yet if (existing.getUserLockedFields() == 0 & isSystemApp) { existing.setBypassDnd(channel.canBypassDnd()); } updateConfig(); return; } Loading @@ -604,9 +622,12 @@ public class RankingHelper implements RankingConfig { || channel.getImportance() > NotificationManager.IMPORTANCE_MAX) { throw new IllegalArgumentException("Invalid importance level"); } // Reset fields that apps aren't allowed to set. if (fromTargetApp) { if (fromTargetApp && !isSystemApp) { channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX); } if (fromTargetApp) { channel.setLockscreenVisibility(r.visibility); } clearLockedFields(channel); Loading @@ -616,6 +637,7 @@ public class RankingHelper implements RankingConfig { if (!r.showBadge) { channel.setShowBadge(false); } r.channels.put(channel.getId(), channel); MetricsLogger.action(getChannelLog(channel, pkg).setType( MetricsProto.MetricsEvent.TYPE_OPEN)); Loading @@ -625,6 +647,65 @@ public class RankingHelper implements RankingConfig { channel.unlockFields(channel.getUserLockedFields()); } /** * Determine whether a package is a "system package", in which case certain things (like * bypassing DND) should be allowed. */ private boolean isSystemPackage(String pkg, int uid) { Pair<String, Integer> app = new Pair(pkg, uid); if (mSystemAppCache.containsKey(app)) { return mSystemAppCache.get(app); } PackageInfo pi; try { pi = mPm.getPackageInfoAsUser( pkg, PackageManager.GET_SIGNATURES, UserHandle.getUserId(uid)); } catch (NameNotFoundException e) { Slog.w(TAG, "Can't find pkg", e); return false; } boolean isSystem = (mSystemSignature[0] != null && mSystemSignature[0].equals(getFirstSignature(pi))) || pkg.equals(mPermissionControllerPackageName) || pkg.equals(mServicesSystemSharedLibPackageName) || pkg.equals(mSharedSystemSharedLibPackageName) || pkg.equals(PrintManager.PRINT_SPOOLER_PACKAGE_NAME) || isDeviceProvisioningPackage(pkg); mSystemAppCache.put(app, isSystem); return isSystem; } private Signature getFirstSignature(PackageInfo pkg) { if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) { return pkg.signatures[0]; } return null; } private Signature getSystemSignature() { try { final PackageInfo sys = mPm.getPackageInfoAsUser( "android", PackageManager.GET_SIGNATURES, UserHandle.USER_SYSTEM); return getFirstSignature(sys); } catch (NameNotFoundException e) { } return null; } private boolean isDeviceProvisioningPackage(String packageName) { String deviceProvisioningPackage = mContext.getResources().getString( com.android.internal.R.string.config_deviceProvisioningPackage); return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName); } private void getSignatures() { mSystemSignature = new Signature[]{getSystemSignature()}; mPermissionControllerPackageName = mPm.getPermissionControllerPackageName(); mServicesSystemSharedLibPackageName = mPm.getServicesSystemSharedLibraryPackageName(); mSharedSystemSharedLibPackageName = mPm.getSharedSystemSharedLibraryPackageName(); } @Override public void updateNotificationChannel(String pkg, int uid, NotificationChannel updatedChannel, boolean fromUser) { Loading
services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java +59 −0 Original line number Diff line number Diff line Loading @@ -47,7 +47,9 @@ import android.content.ContentProvider; import android.content.Context; import android.content.IContentProvider; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.Signature; import android.content.res.Resources; import android.graphics.Color; import android.media.AudioAttributes; Loading Loading @@ -97,6 +99,8 @@ public class RankingHelperTest extends UiServiceTestCase { private static final UserHandle USER = UserHandle.of(0); private static final String UPDATED_PKG = "updatedPkg"; private static final int UID2 = 1111; private static final String SYSTEM_PKG = "android"; private static final int SYSTEM_UID= 1000; private static final UserHandle USER2 = UserHandle.of(10); private static final String TEST_CHANNEL_ID = "test_channel_id"; private static final String TEST_AUTHORITY = "test"; Loading Loading @@ -136,8 +140,15 @@ public class RankingHelperTest extends UiServiceTestCase { upgrade.targetSdkVersion = Build.VERSION_CODES.O; when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy); when(mPm.getApplicationInfoAsUser(eq(UPDATED_PKG), anyInt(), anyInt())).thenReturn(upgrade); when(mPm.getApplicationInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(upgrade); when(mPm.getPackageUidAsUser(eq(PKG), anyInt())).thenReturn(UID); when(mPm.getPackageUidAsUser(eq(UPDATED_PKG), anyInt())).thenReturn(UID2); when(mPm.getPackageUidAsUser(eq(SYSTEM_PKG), anyInt())).thenReturn(SYSTEM_UID); PackageInfo info = mock(PackageInfo.class); info.signatures = new Signature[] {mock(Signature.class)}; when(mPm.getPackageInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(info); when(mPm.getPackageInfoAsUser(eq(PKG), anyInt(), anyInt())) .thenReturn(mock(PackageInfo.class)); when(mContext.getResources()).thenReturn( InstrumentationRegistry.getContext().getResources()); when(mContext.getContentResolver()).thenReturn( Loading Loading @@ -1627,4 +1638,52 @@ public class RankingHelperTest extends UiServiceTestCase { assertEquals(1, retrieved.getChannels().size()); compareChannels(a, findChannel(retrieved.getChannels(), a.getId())); } @Test public void testAndroidPkgCanBypassDnd_creation() { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); test.setBypassDnd(true); mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true); assertTrue(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false) .canBypassDnd()); } @Test public void testNormalPkgCannotBypassDnd_creation() { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); test.setBypassDnd(true); mHelper.createNotificationChannel(PKG, 1000, test, true); assertFalse(mHelper.getNotificationChannel(PKG, 1000, "A", false).canBypassDnd()); } @Test public void testAndroidPkgCanBypassDnd_update() throws Exception { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true); NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); update.setBypassDnd(true); mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, update, true); assertTrue(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false) .canBypassDnd()); // setup + 1st check verify(mPm, times(2)).getPackageInfoAsUser(any(), anyInt(), anyInt()); } @Test public void testNormalPkgCannotBypassDnd_update() { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); mHelper.createNotificationChannel(PKG, 1000, test, true); NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); update.setBypassDnd(true); mHelper.createNotificationChannel(PKG, 1000, update, true); assertFalse(mHelper.getNotificationChannel(PKG, 1000, "A", false).canBypassDnd()); } }