Loading services/core/java/com/android/server/DeviceIdleController.java +88 −0 Original line number Diff line number Diff line Loading @@ -233,6 +233,12 @@ public class DeviceIdleController extends SystemService */ private final ArrayMap<String, Integer> mPowerSaveWhitelistAppsExceptIdle = new ArrayMap<>(); /** * Package names the user has white-listed using commandline option to opt out of * power save restrictions, except for device idle mode. */ private final ArraySet<String> mPowerSaveWhitelistUserAppsExceptIdle = new ArraySet<>(); /** * Package names the system has white-listed to opt out of power save restrictions for * all modes. Loading Loading @@ -1506,6 +1512,45 @@ public class DeviceIdleController extends SystemService } } public boolean addPowerSaveWhitelistExceptIdleInternal(String name) { synchronized (this) { try { final ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(name, PackageManager.MATCH_ANY_USER); if (mPowerSaveWhitelistAppsExceptIdle.put(name, UserHandle.getAppId(ai.uid)) == null) { mPowerSaveWhitelistUserAppsExceptIdle.add(name); reportPowerSaveWhitelistChangedLocked(); mPowerSaveWhitelistExceptIdleAppIdArray = buildAppIdArray( mPowerSaveWhitelistAppsExceptIdle, mPowerSaveWhitelistUserApps, mPowerSaveWhitelistExceptIdleAppIds); } return true; } catch (PackageManager.NameNotFoundException e) { return false; } } } public void resetPowerSaveWhitelistExceptIdleInternal() { synchronized (this) { if (mPowerSaveWhitelistAppsExceptIdle.removeAll( mPowerSaveWhitelistUserAppsExceptIdle)) { reportPowerSaveWhitelistChangedLocked(); mPowerSaveWhitelistExceptIdleAppIdArray = buildAppIdArray( mPowerSaveWhitelistAppsExceptIdle, mPowerSaveWhitelistUserApps, mPowerSaveWhitelistExceptIdleAppIds); mPowerSaveWhitelistUserAppsExceptIdle.clear(); } } } public boolean getPowerSaveWhitelistExceptIdleInternal(String name) { synchronized (this) { return mPowerSaveWhitelistAppsExceptIdle.containsKey(name); } } public String[] getSystemPowerWhitelistExceptIdleInternal() { synchronized (this) { int size = mPowerSaveWhitelistAppsExceptIdle.size(); Loading Loading @@ -2556,6 +2601,12 @@ public class DeviceIdleController extends SystemService pw.println(" Print currently whitelisted apps."); pw.println(" whitelist [package ...]"); pw.println(" Add (prefix with +) or remove (prefix with -) packages."); pw.println(" except-idle-whitelist [package ...|reset]"); pw.println(" Prefix the package with '+' to add it to whitelist or " + "'=' to check if it is already whitelisted"); pw.println(" [reset] will reset the whitelist to it's original state"); pw.println(" Note that unlike <whitelist> cmd, " + "changes made using this won't be persisted across boots"); pw.println(" tempwhitelist"); pw.println(" Print packages that are temporarily whitelisted."); pw.println(" tempwhitelist [-u USER] [-d DURATION] [package ..]"); Loading Loading @@ -2873,6 +2924,43 @@ public class DeviceIdleController extends SystemService } else { dumpTempWhitelistSchedule(pw, false); } } else if ("except-idle-whitelist".equals(cmd)) { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); final long token = Binder.clearCallingIdentity(); try { String arg = shell.getNextArg(); if (arg == null) { pw.println("No arguments given"); return -1; } else if ("reset".equals(arg)) { resetPowerSaveWhitelistExceptIdleInternal(); } else { do { if (arg.length() < 1 || (arg.charAt(0) != '-' && arg.charAt(0) != '+' && arg.charAt(0) != '=')) { pw.println("Package must be prefixed with +, -, or =: " + arg); return -1; } char op = arg.charAt(0); String pkg = arg.substring(1); if (op == '+') { if (addPowerSaveWhitelistExceptIdleInternal(pkg)) { pw.println("Added: " + pkg); } else { pw.println("Unknown package: " + pkg); } } else if (op == '=') { pw.println(getPowerSaveWhitelistExceptIdleInternal(pkg)); } else { pw.println("Unknown argument: " + arg); return -1; } } while ((arg = shell.getNextArg()) != null); } } finally { Binder.restoreCallingIdentity(token); } } else { return shell.handleDefaultCommands(cmd); } Loading services/core/java/com/android/server/notification/NotificationManagerService.java +21 −16 Original line number Diff line number Diff line Loading @@ -1477,7 +1477,7 @@ public class NotificationManagerService extends SystemService { return ; } final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg)); final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg)); final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, Binder.getCallingUid()); Loading Loading @@ -1581,12 +1581,10 @@ public class NotificationManagerService extends SystemService { Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg); // Don't allow client applications to cancel foreground service notis or autobundled // summaries. final int mustNotHaveFlags = isCallingUidSystem() ? 0 : (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY); cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0, (Binder.getCallingUid() == Process.SYSTEM_UID ? 0 : Notification.FLAG_FOREGROUND_SERVICE) | (Binder.getCallingUid() == Process.SYSTEM_UID ? 0 : Notification.FLAG_AUTOGROUP_SUMMARY), false, userId, REASON_APP_CANCEL, null); mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null); } @Override Loading Loading @@ -2452,7 +2450,7 @@ public class NotificationManagerService extends SystemService { } private void enforceSystemOrSystemUI(String message) { if (isCallerSystem()) return; if (isCallerSystemOrPhone()) return; getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, message); } Loading Loading @@ -3276,7 +3274,7 @@ public class NotificationManagerService extends SystemService { private int resolveNotificationUid(String opPackageName, int callingUid, int userId) { // The system can post notifications on behalf of any package it wants if (isCallerSystem() && opPackageName != null && !"android".equals(opPackageName)) { if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) { try { return getContext().getPackageManager() .getPackageUidAsUser(opPackageName, userId); Loading @@ -3295,7 +3293,8 @@ public class NotificationManagerService extends SystemService { private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag, NotificationRecord r) { final String pkg = r.sbn.getPackageName(); final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg)); final boolean isSystemNotification = isUidSystemOrPhone(callingUid) || ("android".equals(pkg)); final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg); // Limit the number of notifications that any given package except the android Loading Loading @@ -4192,7 +4191,7 @@ public class NotificationManagerService extends SystemService { mNotificationsByKey.remove(recordInList.sbn.getKey()); wasPosted = true; } if ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey())) while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey())) != null) { mEnqueuedNotifications.remove(recordInList); } Loading Loading @@ -4690,24 +4689,30 @@ public class NotificationManagerService extends SystemService { } } protected boolean isUidSystem(int uid) { protected boolean isCallingUidSystem() { final int uid = Binder.getCallingUid(); return uid == Process.SYSTEM_UID; } protected boolean isUidSystemOrPhone(int uid) { final int appid = UserHandle.getAppId(uid); return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0); } protected boolean isCallerSystem() { return isUidSystem(Binder.getCallingUid()); // TODO: Most calls should probably move to isCallerSystem. protected boolean isCallerSystemOrPhone() { return isUidSystemOrPhone(Binder.getCallingUid()); } private void checkCallerIsSystem() { if (isCallerSystem()) { if (isCallerSystemOrPhone()) { return; } throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid()); } private void checkCallerIsSystemOrSameApp(String pkg) { if (isCallerSystem()) { if (isCallerSystemOrPhone()) { return; } checkCallerIsSameApp(pkg); Loading @@ -4715,7 +4720,7 @@ public class NotificationManagerService extends SystemService { private boolean isCallerInstantApp(String pkg) { // System is always allowed to act for ephemeral apps. if (isCallerSystem()) { if (isCallerSystemOrPhone()) { return false; } Loading services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java +21 −2 Original line number Diff line number Diff line Loading @@ -104,7 +104,12 @@ public class NotificationManagerServiceTest { public TestableNotificationManagerService(Context context) { super(context); } @Override protected boolean isCallerSystem() { protected boolean isCallingUidSystem() { return true; } @Override protected boolean isCallerSystemOrPhone() { return true; } Loading Loading @@ -410,6 +415,21 @@ public class NotificationManagerServiceTest { assertEquals(0, notifs[0].getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE); } @Test public void testCancelAfterSecondEnqueueDoesNotSpecifyForegroundFlag() throws Exception { final StatusBarNotification sbn = generateNotificationRecord(null).sbn; sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE; mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT; mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); mBinderService.cancelNotificationWithTag(PKG, "tag", sbn.getId(), sbn.getUserId()); waitForIdle(); assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); } @Test public void testFindGroupNotificationsLocked() throws Exception { // make sure the same notification can be found in both lists and returned Loading Loading @@ -449,7 +469,6 @@ public class NotificationManagerServiceTest { } } @Test public void testTvExtenderChannelOverride_onTv() throws Exception { mNotificationManagerService.setIsTelevision(true); Loading Loading
services/core/java/com/android/server/DeviceIdleController.java +88 −0 Original line number Diff line number Diff line Loading @@ -233,6 +233,12 @@ public class DeviceIdleController extends SystemService */ private final ArrayMap<String, Integer> mPowerSaveWhitelistAppsExceptIdle = new ArrayMap<>(); /** * Package names the user has white-listed using commandline option to opt out of * power save restrictions, except for device idle mode. */ private final ArraySet<String> mPowerSaveWhitelistUserAppsExceptIdle = new ArraySet<>(); /** * Package names the system has white-listed to opt out of power save restrictions for * all modes. Loading Loading @@ -1506,6 +1512,45 @@ public class DeviceIdleController extends SystemService } } public boolean addPowerSaveWhitelistExceptIdleInternal(String name) { synchronized (this) { try { final ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(name, PackageManager.MATCH_ANY_USER); if (mPowerSaveWhitelistAppsExceptIdle.put(name, UserHandle.getAppId(ai.uid)) == null) { mPowerSaveWhitelistUserAppsExceptIdle.add(name); reportPowerSaveWhitelistChangedLocked(); mPowerSaveWhitelistExceptIdleAppIdArray = buildAppIdArray( mPowerSaveWhitelistAppsExceptIdle, mPowerSaveWhitelistUserApps, mPowerSaveWhitelistExceptIdleAppIds); } return true; } catch (PackageManager.NameNotFoundException e) { return false; } } } public void resetPowerSaveWhitelistExceptIdleInternal() { synchronized (this) { if (mPowerSaveWhitelistAppsExceptIdle.removeAll( mPowerSaveWhitelistUserAppsExceptIdle)) { reportPowerSaveWhitelistChangedLocked(); mPowerSaveWhitelistExceptIdleAppIdArray = buildAppIdArray( mPowerSaveWhitelistAppsExceptIdle, mPowerSaveWhitelistUserApps, mPowerSaveWhitelistExceptIdleAppIds); mPowerSaveWhitelistUserAppsExceptIdle.clear(); } } } public boolean getPowerSaveWhitelistExceptIdleInternal(String name) { synchronized (this) { return mPowerSaveWhitelistAppsExceptIdle.containsKey(name); } } public String[] getSystemPowerWhitelistExceptIdleInternal() { synchronized (this) { int size = mPowerSaveWhitelistAppsExceptIdle.size(); Loading Loading @@ -2556,6 +2601,12 @@ public class DeviceIdleController extends SystemService pw.println(" Print currently whitelisted apps."); pw.println(" whitelist [package ...]"); pw.println(" Add (prefix with +) or remove (prefix with -) packages."); pw.println(" except-idle-whitelist [package ...|reset]"); pw.println(" Prefix the package with '+' to add it to whitelist or " + "'=' to check if it is already whitelisted"); pw.println(" [reset] will reset the whitelist to it's original state"); pw.println(" Note that unlike <whitelist> cmd, " + "changes made using this won't be persisted across boots"); pw.println(" tempwhitelist"); pw.println(" Print packages that are temporarily whitelisted."); pw.println(" tempwhitelist [-u USER] [-d DURATION] [package ..]"); Loading Loading @@ -2873,6 +2924,43 @@ public class DeviceIdleController extends SystemService } else { dumpTempWhitelistSchedule(pw, false); } } else if ("except-idle-whitelist".equals(cmd)) { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); final long token = Binder.clearCallingIdentity(); try { String arg = shell.getNextArg(); if (arg == null) { pw.println("No arguments given"); return -1; } else if ("reset".equals(arg)) { resetPowerSaveWhitelistExceptIdleInternal(); } else { do { if (arg.length() < 1 || (arg.charAt(0) != '-' && arg.charAt(0) != '+' && arg.charAt(0) != '=')) { pw.println("Package must be prefixed with +, -, or =: " + arg); return -1; } char op = arg.charAt(0); String pkg = arg.substring(1); if (op == '+') { if (addPowerSaveWhitelistExceptIdleInternal(pkg)) { pw.println("Added: " + pkg); } else { pw.println("Unknown package: " + pkg); } } else if (op == '=') { pw.println(getPowerSaveWhitelistExceptIdleInternal(pkg)); } else { pw.println("Unknown argument: " + arg); return -1; } } while ((arg = shell.getNextArg()) != null); } } finally { Binder.restoreCallingIdentity(token); } } else { return shell.handleDefaultCommands(cmd); } Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +21 −16 Original line number Diff line number Diff line Loading @@ -1477,7 +1477,7 @@ public class NotificationManagerService extends SystemService { return ; } final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg)); final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg)); final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, Binder.getCallingUid()); Loading Loading @@ -1581,12 +1581,10 @@ public class NotificationManagerService extends SystemService { Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg); // Don't allow client applications to cancel foreground service notis or autobundled // summaries. final int mustNotHaveFlags = isCallingUidSystem() ? 0 : (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY); cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0, (Binder.getCallingUid() == Process.SYSTEM_UID ? 0 : Notification.FLAG_FOREGROUND_SERVICE) | (Binder.getCallingUid() == Process.SYSTEM_UID ? 0 : Notification.FLAG_AUTOGROUP_SUMMARY), false, userId, REASON_APP_CANCEL, null); mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null); } @Override Loading Loading @@ -2452,7 +2450,7 @@ public class NotificationManagerService extends SystemService { } private void enforceSystemOrSystemUI(String message) { if (isCallerSystem()) return; if (isCallerSystemOrPhone()) return; getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, message); } Loading Loading @@ -3276,7 +3274,7 @@ public class NotificationManagerService extends SystemService { private int resolveNotificationUid(String opPackageName, int callingUid, int userId) { // The system can post notifications on behalf of any package it wants if (isCallerSystem() && opPackageName != null && !"android".equals(opPackageName)) { if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) { try { return getContext().getPackageManager() .getPackageUidAsUser(opPackageName, userId); Loading @@ -3295,7 +3293,8 @@ public class NotificationManagerService extends SystemService { private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag, NotificationRecord r) { final String pkg = r.sbn.getPackageName(); final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg)); final boolean isSystemNotification = isUidSystemOrPhone(callingUid) || ("android".equals(pkg)); final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg); // Limit the number of notifications that any given package except the android Loading Loading @@ -4192,7 +4191,7 @@ public class NotificationManagerService extends SystemService { mNotificationsByKey.remove(recordInList.sbn.getKey()); wasPosted = true; } if ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey())) while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey())) != null) { mEnqueuedNotifications.remove(recordInList); } Loading Loading @@ -4690,24 +4689,30 @@ public class NotificationManagerService extends SystemService { } } protected boolean isUidSystem(int uid) { protected boolean isCallingUidSystem() { final int uid = Binder.getCallingUid(); return uid == Process.SYSTEM_UID; } protected boolean isUidSystemOrPhone(int uid) { final int appid = UserHandle.getAppId(uid); return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0); } protected boolean isCallerSystem() { return isUidSystem(Binder.getCallingUid()); // TODO: Most calls should probably move to isCallerSystem. protected boolean isCallerSystemOrPhone() { return isUidSystemOrPhone(Binder.getCallingUid()); } private void checkCallerIsSystem() { if (isCallerSystem()) { if (isCallerSystemOrPhone()) { return; } throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid()); } private void checkCallerIsSystemOrSameApp(String pkg) { if (isCallerSystem()) { if (isCallerSystemOrPhone()) { return; } checkCallerIsSameApp(pkg); Loading @@ -4715,7 +4720,7 @@ public class NotificationManagerService extends SystemService { private boolean isCallerInstantApp(String pkg) { // System is always allowed to act for ephemeral apps. if (isCallerSystem()) { if (isCallerSystemOrPhone()) { return false; } Loading
services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java +21 −2 Original line number Diff line number Diff line Loading @@ -104,7 +104,12 @@ public class NotificationManagerServiceTest { public TestableNotificationManagerService(Context context) { super(context); } @Override protected boolean isCallerSystem() { protected boolean isCallingUidSystem() { return true; } @Override protected boolean isCallerSystemOrPhone() { return true; } Loading Loading @@ -410,6 +415,21 @@ public class NotificationManagerServiceTest { assertEquals(0, notifs[0].getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE); } @Test public void testCancelAfterSecondEnqueueDoesNotSpecifyForegroundFlag() throws Exception { final StatusBarNotification sbn = generateNotificationRecord(null).sbn; sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE; mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT; mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); mBinderService.cancelNotificationWithTag(PKG, "tag", sbn.getId(), sbn.getUserId()); waitForIdle(); assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); } @Test public void testFindGroupNotificationsLocked() throws Exception { // make sure the same notification can be found in both lists and returned Loading Loading @@ -449,7 +469,6 @@ public class NotificationManagerServiceTest { } } @Test public void testTvExtenderChannelOverride_onTv() throws Exception { mNotificationManagerService.setIsTelevision(true); Loading