Loading services/core/java/com/android/server/notification/NotificationManagerService.java +21 −0 Original line number Diff line number Diff line Loading @@ -4031,6 +4031,7 @@ public class NotificationManagerService extends SystemService { + " notification=" + notification); } checkCallerIsSystemOrSameApp(pkg); checkRestrictedCategories(notification); final int userId = ActivityManager.handleIncomingUser(callingPid, callingUid, incomingUserId, true, false, "enqueueNotification", pkg); Loading Loading @@ -6197,6 +6198,26 @@ public class NotificationManagerService extends SystemService { checkCallerIsSameApp(pkg); } /** * Check if the notification is of a category type that is restricted to system use only, * if so throw SecurityException */ private void checkRestrictedCategories(final Notification notification) { try { if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) { return; } } catch (RemoteException re) { if (DBG) Log.e(TAG, "Unable to confirm if it's safe to skip category " + "restrictions check thus the check will be done anyway"); } if (Notification.CATEGORY_CAR_EMERGENCY.equals(notification.category) || Notification.CATEGORY_CAR_WARNING.equals(notification.category) || Notification.CATEGORY_CAR_INFORMATION.equals(notification.category)) { checkCallerIsSystem(); } } private boolean isCallerInstantApp(String pkg) { // System is always allowed to act for ephemeral apps. if (isCallerSystemOrPhone()) { Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +77 −2 Original line number Diff line number Diff line Loading @@ -111,6 +111,7 @@ import android.testing.TestableLooper.RunWithLooper; import android.text.Html; import android.util.ArrayMap; import android.util.AtomicFile; import android.util.Log; import com.android.internal.R; import com.android.internal.statusbar.NotificationVisibility; Loading Loading @@ -199,6 +200,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Use a Testable subclass so we can simulate calls from the system without failing. private static class TestableNotificationManagerService extends NotificationManagerService { int countSystemChecks = 0; boolean isSystemUid = true; public TestableNotificationManagerService(Context context) { super(context); Loading @@ -207,13 +209,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Override protected boolean isCallingUidSystem() { countSystemChecks++; return true; return isSystemUid; } @Override protected boolean isCallerSystemOrPhone() { countSystemChecks++; return true; return isSystemUid; } @Override Loading Loading @@ -651,6 +653,79 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertNull(mService.getNotificationRecord(sbn.getKey())); } /** * Confirm the system user on automotive devices can use car categories */ @Test public void testEnqueuedRestrictedNotifications_asSystem() throws Exception { when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) .thenReturn(true); List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY, Notification.CATEGORY_CAR_WARNING, Notification.CATEGORY_CAR_INFORMATION); int id = 0; for (String category: categories) { final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, ++id, "", false).sbn; sbn.getNotification().category = category; mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); } waitForIdle(); assertEquals(categories.size(), mBinderService.getActiveNotifications(PKG).length); } /** * Confirm restricted notification categories only apply to automotive. */ @Test public void testEnqueuedRestrictedNotifications_notAutomotive() throws Exception { mService.isSystemUid = false; when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) .thenReturn(false); List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY, Notification.CATEGORY_CAR_WARNING, Notification.CATEGORY_CAR_INFORMATION); int id = 0; for (String category: categories) { final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, ++id, "", false).sbn; sbn.getNotification().category = category; mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); } waitForIdle(); assertEquals(categories.size(), mBinderService.getActiveNotifications(PKG).length); } /** * Confirm if a non-system user tries to use the car categories on a automotive device that * they will get a security exception */ @Test public void testEnqueuedRestrictedNotifications_badUser() throws Exception { mService.isSystemUid = false; when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) .thenReturn(true); List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY, Notification.CATEGORY_CAR_WARNING, Notification.CATEGORY_CAR_INFORMATION); for (String category: categories) { final StatusBarNotification sbn = generateNotificationRecord(null).sbn; sbn.getNotification().category = category; try { mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); fail("Calls from non system apps should not allow use of restricted categories"); } catch (SecurityException e) { // pass } } waitForIdle(); assertEquals(0, mBinderService.getActiveNotifications(PKG).length); } @Test public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception { mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0, Loading Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +21 −0 Original line number Diff line number Diff line Loading @@ -4031,6 +4031,7 @@ public class NotificationManagerService extends SystemService { + " notification=" + notification); } checkCallerIsSystemOrSameApp(pkg); checkRestrictedCategories(notification); final int userId = ActivityManager.handleIncomingUser(callingPid, callingUid, incomingUserId, true, false, "enqueueNotification", pkg); Loading Loading @@ -6197,6 +6198,26 @@ public class NotificationManagerService extends SystemService { checkCallerIsSameApp(pkg); } /** * Check if the notification is of a category type that is restricted to system use only, * if so throw SecurityException */ private void checkRestrictedCategories(final Notification notification) { try { if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) { return; } } catch (RemoteException re) { if (DBG) Log.e(TAG, "Unable to confirm if it's safe to skip category " + "restrictions check thus the check will be done anyway"); } if (Notification.CATEGORY_CAR_EMERGENCY.equals(notification.category) || Notification.CATEGORY_CAR_WARNING.equals(notification.category) || Notification.CATEGORY_CAR_INFORMATION.equals(notification.category)) { checkCallerIsSystem(); } } private boolean isCallerInstantApp(String pkg) { // System is always allowed to act for ephemeral apps. if (isCallerSystemOrPhone()) { Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +77 −2 Original line number Diff line number Diff line Loading @@ -111,6 +111,7 @@ import android.testing.TestableLooper.RunWithLooper; import android.text.Html; import android.util.ArrayMap; import android.util.AtomicFile; import android.util.Log; import com.android.internal.R; import com.android.internal.statusbar.NotificationVisibility; Loading Loading @@ -199,6 +200,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Use a Testable subclass so we can simulate calls from the system without failing. private static class TestableNotificationManagerService extends NotificationManagerService { int countSystemChecks = 0; boolean isSystemUid = true; public TestableNotificationManagerService(Context context) { super(context); Loading @@ -207,13 +209,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Override protected boolean isCallingUidSystem() { countSystemChecks++; return true; return isSystemUid; } @Override protected boolean isCallerSystemOrPhone() { countSystemChecks++; return true; return isSystemUid; } @Override Loading Loading @@ -651,6 +653,79 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertNull(mService.getNotificationRecord(sbn.getKey())); } /** * Confirm the system user on automotive devices can use car categories */ @Test public void testEnqueuedRestrictedNotifications_asSystem() throws Exception { when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) .thenReturn(true); List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY, Notification.CATEGORY_CAR_WARNING, Notification.CATEGORY_CAR_INFORMATION); int id = 0; for (String category: categories) { final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, ++id, "", false).sbn; sbn.getNotification().category = category; mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); } waitForIdle(); assertEquals(categories.size(), mBinderService.getActiveNotifications(PKG).length); } /** * Confirm restricted notification categories only apply to automotive. */ @Test public void testEnqueuedRestrictedNotifications_notAutomotive() throws Exception { mService.isSystemUid = false; when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) .thenReturn(false); List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY, Notification.CATEGORY_CAR_WARNING, Notification.CATEGORY_CAR_INFORMATION); int id = 0; for (String category: categories) { final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, ++id, "", false).sbn; sbn.getNotification().category = category; mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); } waitForIdle(); assertEquals(categories.size(), mBinderService.getActiveNotifications(PKG).length); } /** * Confirm if a non-system user tries to use the car categories on a automotive device that * they will get a security exception */ @Test public void testEnqueuedRestrictedNotifications_badUser() throws Exception { mService.isSystemUid = false; when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) .thenReturn(true); List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY, Notification.CATEGORY_CAR_WARNING, Notification.CATEGORY_CAR_INFORMATION); for (String category: categories) { final StatusBarNotification sbn = generateNotificationRecord(null).sbn; sbn.getNotification().category = category; try { mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); fail("Calls from non system apps should not allow use of restricted categories"); } catch (SecurityException e) { // pass } } waitForIdle(); assertEquals(0, mBinderService.getActiveNotifications(PKG).length); } @Test public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception { mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0, Loading