diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl index 838279bf38f91..082194ba6162a 100644 --- a/core/java/android/os/IDeviceIdleController.aidl +++ b/core/java/android/os/IDeviceIdleController.aidl @@ -25,10 +25,12 @@ interface IDeviceIdleController { void removePowerSaveWhitelistApp(String name); String[] getSystemPowerWhitelistExceptIdle(); String[] getSystemPowerWhitelist(); + String[] getUserPowerWhitelist(); String[] getFullPowerWhitelistExceptIdle(); String[] getFullPowerWhitelist(); int[] getAppIdWhitelistExceptIdle(); int[] getAppIdWhitelist(); + int[] getAppIdUserWhitelist(); int[] getAppIdTempWhitelist(); boolean isPowerSaveWhitelistExceptIdleApp(String name); boolean isPowerSaveWhitelistApp(String name); diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 46671729a2ef0..c5a210c6802dd 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -149,6 +149,12 @@ class AlarmManagerService extends SystemService { long mAllowWhileIdleMinTime; int mNumTimeChanged; + /** + * The current set of user whitelisted apps for device idle mode, meaning these are allowed + * to freely schedule alarms. + */ + int[] mDeviceIdleUserWhitelist = new int[0]; + /** * For each uid, this is the last time we dispatched an "allow while idle" alarm, * used to determine the earliest we can dispatch the next such alarm. @@ -936,6 +942,7 @@ class AlarmManagerService extends SystemService { } publishBinderService(Context.ALARM_SERVICE, mService); + publishLocalService(LocalService.class, new LocalService()); } @Override @@ -1251,14 +1258,6 @@ class AlarmManagerService extends SystemService { flags &= ~AlarmManager.FLAG_IDLE_UNTIL; } - // If the caller is a core system component, and not calling to do work on behalf - // of someone else, then always set ALLOW_WHILE_IDLE_UNRESTRICTED. This means we - // will allow these alarms to go off as normal even while idle, with no timing - // restrictions. - if (callingUid < Process.FIRST_APPLICATION_UID && workSource == null) { - flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED; - } - // If this is an exact time alarm, then it can't be batched with other alarms. if (windowLength == AlarmManager.WINDOW_EXACT) { flags |= AlarmManager.FLAG_STANDALONE; @@ -1268,6 +1267,16 @@ class AlarmManagerService extends SystemService { // use it to wake early from idle if needed. if (alarmClock != null) { flags |= AlarmManager.FLAG_WAKE_FROM_IDLE | AlarmManager.FLAG_STANDALONE; + + // If the caller is a core system component or on the user's whitelist, and not calling + // to do work on behalf of someone else, then always set ALLOW_WHILE_IDLE_UNRESTRICTED. + // This means we will allow these alarms to go off as normal even while idle, with no + // timing restrictions. + } else if (workSource == null && (callingUid < Process.FIRST_APPLICATION_UID + || Arrays.binarySearch(mDeviceIdleUserWhitelist, + UserHandle.getAppId(callingUid)) >= 0)) { + flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED; + flags &= ~AlarmManager.FLAG_ALLOW_WHILE_IDLE; } setImpl(type, triggerAtTime, windowLength, interval, operation, directReceiver, @@ -1344,6 +1353,12 @@ class AlarmManagerService extends SystemService { } }; + public final class LocalService { + public void setDeviceIdleUserWhitelist(int[] appids) { + setDeviceIdleUserWhitelistImpl(appids); + } + } + void dumpImpl(PrintWriter pw) { synchronized (mLock) { pw.println("Current Alarm Manager state:"); @@ -1386,6 +1401,7 @@ class AlarmManagerService extends SystemService { pw.print(" Next wakeup: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw); pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC))); pw.print(" Num time change events: "); pw.println(mNumTimeChanged); + pw.println(" mDeviceIdleUserWhitelist=" + Arrays.toString(mDeviceIdleUserWhitelist)); pw.println(); pw.println(" Next alarm clock information: "); @@ -1678,6 +1694,12 @@ class AlarmManagerService extends SystemService { } } + void setDeviceIdleUserWhitelistImpl(int[] appids) { + synchronized (mLock) { + mDeviceIdleUserWhitelist = appids; + } + } + AlarmManager.AlarmClockInfo getNextAlarmClockImpl(int userId) { synchronized (mLock) { return mNextAlarmClockForUser.get(userId); diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 62fa7d5af754c..7bf4b56c03d18 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -120,6 +120,7 @@ public class DeviceIdleController extends SystemService private AlarmManager mAlarmManager; private IBatteryStats mBatteryStats; private PowerManagerInternal mLocalPowerManager; + private AlarmManagerService.LocalService mLocalAlarmManager; private INetworkPolicyManager mNetworkPolicyManager; private DisplayManager mDisplayManager; private SensorManager mSensorManager; @@ -268,6 +269,17 @@ public class DeviceIdleController extends SystemService */ private int[] mPowerSaveWhitelistAllAppIdArray = new int[0]; + /** + * App IDs that have been white-listed by the user to opt out of power save restrictions. + */ + private final SparseBooleanArray mPowerSaveWhitelistUserAppIds = new SparseBooleanArray(); + + /** + * Current app IDs that are in the user power save white list. This array can + * be shared with others because it will not be modified once set. + */ + private int[] mPowerSaveWhitelistUserAppIdArray = new int[0]; + /** * List of end times for UIDs that are temporarily marked as being allowed to access * the network and acquire wakelocks. Times are in milliseconds. @@ -964,6 +976,10 @@ public class DeviceIdleController extends SystemService return getSystemPowerWhitelistInternal(); } + @Override public String[] getUserPowerWhitelist() { + return getUserPowerWhitelistInternal(); + } + @Override public String[] getFullPowerWhitelistExceptIdle() { return getFullPowerWhitelistExceptIdleInternal(); } @@ -980,6 +996,10 @@ public class DeviceIdleController extends SystemService return getAppIdWhitelistInternal(); } + @Override public int[] getAppIdUserWhitelist() { + return getAppIdUserWhitelistInternal(); + } + @Override public int[] getAppIdTempWhitelist() { return getAppIdTempWhitelistInternal(); } @@ -1161,6 +1181,7 @@ public class DeviceIdleController extends SystemService mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); mBatteryStats = BatteryStatsService.getService(); mLocalPowerManager = getLocalService(PowerManagerInternal.class); + mLocalAlarmManager = getLocalService(AlarmManagerService.LocalService.class); mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface( ServiceManager.getService(Context.NETWORK_POLICY_SERVICE)); mDisplayManager = (DisplayManager) getContext().getSystemService( @@ -1227,6 +1248,7 @@ public class DeviceIdleController extends SystemService getContext().registerReceiver(mReceiver, filter); mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray); + mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray); mDisplayManager.registerDisplayListener(mDisplayListener, null); updateDisplayLocked(); @@ -1291,6 +1313,17 @@ public class DeviceIdleController extends SystemService } } + public String[] getUserPowerWhitelistInternal() { + synchronized (this) { + int size = mPowerSaveWhitelistUserApps.size(); + String[] apps = new String[size]; + for (int i = 0; i < mPowerSaveWhitelistUserApps.size(); i++) { + apps[i] = mPowerSaveWhitelistUserApps.keyAt(i); + } + return apps; + } + } + public String[] getFullPowerWhitelistExceptIdleInternal() { synchronized (this) { int size = mPowerSaveWhitelistAppsExceptIdle.size() + mPowerSaveWhitelistUserApps.size(); @@ -1351,6 +1384,12 @@ public class DeviceIdleController extends SystemService } } + public int[] getAppIdUserWhitelistInternal() { + synchronized (this) { + return mPowerSaveWhitelistUserAppIdArray; + } + } + public int[] getAppIdTempWhitelistInternal() { synchronized (this) { return mTempWhitelistAppIdArray; @@ -1993,11 +2032,15 @@ public class DeviceIdleController extends SystemService private static int[] buildAppIdArray(ArrayMap systemApps, ArrayMap userApps, SparseBooleanArray outAppIds) { outAppIds.clear(); - for (int i=0; i 0) { + pw.println(" Whitelist user app ids:"); + for (int i = 0; i < size; i++) { + pw.print(" "); + pw.print(mPowerSaveWhitelistUserAppIds.keyAt(i)); + pw.println(); + } + } size = mPowerSaveWhitelistAllAppIds.size(); if (size > 0) { pw.println(" Whitelist all app ids:");