DO NOT MERGE: Add separate information about user whitelist.
Use this in the alarm manager to allow user whitelisted apps
to have free access to scheduling alarms.
Coming next: lifting sync/job restrictions.
Bug #26851107: Allow user whitelist apps more freedom
(Cherry-picked to nyc since it got lost in the branch from master.)
Change-Id: I4dc9f07514627ebdb6b6eff7c7a749f2c51a3797
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 4667172..c5a210c 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -150,6 +150,12 @@
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 @@
}
publishBinderService(Context.ALARM_SERVICE, mService);
+ publishLocalService(LocalService.class, new LocalService());
}
@Override
@@ -1251,14 +1258,6 @@
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 @@
// 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 @@
}
};
+ 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 @@
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 @@
}
}
+ 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 62fa7d5..7bf4b56 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -120,6 +120,7 @@
private AlarmManager mAlarmManager;
private IBatteryStats mBatteryStats;
private PowerManagerInternal mLocalPowerManager;
+ private AlarmManagerService.LocalService mLocalAlarmManager;
private INetworkPolicyManager mNetworkPolicyManager;
private DisplayManager mDisplayManager;
private SensorManager mSensorManager;
@@ -269,6 +270,17 @@
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 @@
return getSystemPowerWhitelistInternal();
}
+ @Override public String[] getUserPowerWhitelist() {
+ return getUserPowerWhitelistInternal();
+ }
+
@Override public String[] getFullPowerWhitelistExceptIdle() {
return getFullPowerWhitelistExceptIdleInternal();
}
@@ -980,6 +996,10 @@
return getAppIdWhitelistInternal();
}
+ @Override public int[] getAppIdUserWhitelist() {
+ return getAppIdUserWhitelistInternal();
+ }
+
@Override public int[] getAppIdTempWhitelist() {
return getAppIdTempWhitelistInternal();
}
@@ -1161,6 +1181,7 @@
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 @@
getContext().registerReceiver(mReceiver, filter);
mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
+ mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray);
mDisplayManager.registerDisplayListener(mDisplayListener, null);
updateDisplayLocked();
@@ -1291,6 +1313,17 @@
}
}
+ 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 int[] getAppIdUserWhitelistInternal() {
+ synchronized (this) {
+ return mPowerSaveWhitelistUserAppIdArray;
+ }
+ }
+
public int[] getAppIdTempWhitelistInternal() {
synchronized (this) {
return mTempWhitelistAppIdArray;
@@ -1993,11 +2032,15 @@
private static int[] buildAppIdArray(ArrayMap<String, Integer> systemApps,
ArrayMap<String, Integer> userApps, SparseBooleanArray outAppIds) {
outAppIds.clear();
- for (int i=0; i<systemApps.size(); i++) {
- outAppIds.put(systemApps.valueAt(i), true);
+ if (systemApps != null) {
+ for (int i = 0; i < systemApps.size(); i++) {
+ outAppIds.put(systemApps.valueAt(i), true);
+ }
}
- for (int i=0; i<userApps.size(); i++) {
- outAppIds.put(userApps.valueAt(i), true);
+ if (userApps != null) {
+ for (int i = 0; i < userApps.size(); i++) {
+ outAppIds.put(userApps.valueAt(i), true);
+ }
}
int size = outAppIds.size();
int[] appids = new int[size];
@@ -2012,6 +2055,8 @@
mPowerSaveWhitelistUserApps, mPowerSaveWhitelistExceptIdleAppIds);
mPowerSaveWhitelistAllAppIdArray = buildAppIdArray(mPowerSaveWhitelistApps,
mPowerSaveWhitelistUserApps, mPowerSaveWhitelistAllAppIds);
+ mPowerSaveWhitelistUserAppIdArray = buildAppIdArray(null,
+ mPowerSaveWhitelistUserApps, mPowerSaveWhitelistUserAppIds);
if (mLocalPowerManager != null) {
if (DEBUG) {
Slog.d(TAG, "Setting wakelock whitelist to "
@@ -2019,6 +2064,13 @@
}
mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
}
+ if (mLocalAlarmManager != null) {
+ if (DEBUG) {
+ Slog.d(TAG, "Setting alarm whitelist to "
+ + Arrays.toString(mPowerSaveWhitelistUserAppIdArray));
+ }
+ mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray);
+ }
}
private void updateTempWhitelistAppIdsLocked() {
@@ -2536,6 +2588,15 @@
pw.println();
}
}
+ size = mPowerSaveWhitelistUserAppIds.size();
+ if (size > 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:");