summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2015-05-08 17:21:48 -0700
committerDianne Hackborn <hackbod@google.com>2015-05-11 15:16:47 -0700
commit8d66b3fbf5d8036e25d64a8472bcd2b6b7892a1a (patch)
treecc4aa1432f4abecd3b7d34275945a0c1c678fd34 /services
parentcfd6e9dfd063cba795497f251aa6f7fe2554f10b (diff)
downloadframeworks_base-8d66b3fbf5d8036e25d64a8472bcd2b6b7892a1a.zip
frameworks_base-8d66b3fbf5d8036e25d64a8472bcd2b6b7892a1a.tar.gz
frameworks_base-8d66b3fbf5d8036e25d64a8472bcd2b6b7892a1a.tar.bz2
Implement device idle in power manager.
When in device idle mode, we now prevent most apps from being able to hold partial wake locks. The device idle controller now pushes its white list of app uids into the power manager, so it can apply this policy correctly to only apps that are not whitelisted. The implementation adds a new "disabled" flag to a wake lock which is set when we want to apply this policy. When set, we ensure that we tell battery stats that the wake lock is not being held and ignore that wake lock when computing the power state summary. Also add new SDK APIs to schedule alarms that are allowed to execute while in idle mode. Finally add new dumpsys commands to the device idle controller to completely disable and re-enable its operation, to use for testing. Change-Id: I1f16672c6ac06d03bb538f9854d5843db9aa6f27
Diffstat (limited to 'services')
-rw-r--r--services/core/java/com/android/server/DeviceIdleController.java54
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java93
2 files changed, 131 insertions, 16 deletions
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index b7bc0f0..76465d4 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -142,6 +142,7 @@ public class DeviceIdleController extends SystemService {
private PendingIntent mAlarmIntent;
private Intent mIdleIntent;
private Display mCurDisplay;
+ private boolean mIdleDisabled;
private boolean mScreenOn;
private boolean mCharging;
private boolean mSigMotionActive;
@@ -187,10 +188,16 @@ public class DeviceIdleController extends SystemService {
private final ArrayMap<String, Integer> mPowerSaveWhitelistUserApps = new ArrayMap<>();
/**
- * UIDs that have been white-listed to opt out of power save restrictions.
+ * App IDs that have been white-listed to opt out of power save restrictions.
*/
private final SparseBooleanArray mPowerSaveWhitelistAppIds = new SparseBooleanArray();
+ /**
+ * Current app IDs that are in the complete power save white list. This array can
+ * be shared with others because it will not be modified once set.
+ */
+ private int[] mPowerSaveWhitelistAppIdArray = new int[0];
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
@@ -381,6 +388,8 @@ public class DeviceIdleController extends SystemService {
filter.addAction(ACTION_STEP_IDLE_STATE);
getContext().registerReceiver(mReceiver, filter);
+ mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAppIdArray);
+
mDisplayManager.registerDisplayListener(mDisplayListener, null);
updateDisplayLocked();
}
@@ -445,12 +454,7 @@ public class DeviceIdleController extends SystemService {
public int[] getAppIdWhitelistInternal() {
synchronized (this) {
- int size = mPowerSaveWhitelistAppIds.size();
- int[] appids = new int[size];
- for (int i = 0; i < size; i++) {
- appids[i] = mPowerSaveWhitelistAppIds.keyAt(i);
- }
- return appids;
+ return mPowerSaveWhitelistAppIdArray;
}
}
@@ -499,7 +503,7 @@ public class DeviceIdleController extends SystemService {
}
void becomeInactiveIfAppropriateLocked() {
- if (!mScreenOn && !mCharging && mState == STATE_ACTIVE) {
+ if (!mScreenOn && !mCharging && !mIdleDisabled && mState == STATE_ACTIVE) {
// Screen has turned off; we are now going to become inactive and start
// waiting to see if we will ultimately go idle.
mState = STATE_INACTIVE;
@@ -625,6 +629,15 @@ public class DeviceIdleController extends SystemService {
for (int i=0; i<mPowerSaveWhitelistUserApps.size(); i++) {
mPowerSaveWhitelistAppIds.put(mPowerSaveWhitelistUserApps.valueAt(i), true);
}
+ int size = mPowerSaveWhitelistAppIds.size();
+ int[] appids = new int[size];
+ for (int i = 0; i < size; i++) {
+ appids[i] = mPowerSaveWhitelistAppIds.keyAt(i);
+ }
+ mPowerSaveWhitelistAppIdArray = appids;
+ if (mLocalPowerManager != null) {
+ mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAppIdArray);
+ }
}
private void reportPowerSaveWhitelistChangedLocked() {
@@ -763,6 +776,10 @@ public class DeviceIdleController extends SystemService {
pw.println("Commands:");
pw.println(" step");
pw.println(" Immediately step to next state, without waiting for alarm.");
+ pw.println(" disable");
+ pw.println(" Completely disable device idle mode.");
+ pw.println(" enable");
+ pw.println(" Re-enable device idle mode after it had previously been disabled.");
pw.println(" whitelist");
pw.println(" Add (prefix with +) or remove (prefix with -) packages.");
}
@@ -782,12 +799,32 @@ public class DeviceIdleController extends SystemService {
if ("-h".equals(arg)) {
dumpHelp(pw);
return;
+ } else if ("-a".equals(arg)) {
+ // Ignore, we always dump all.
} else if ("step".equals(arg)) {
synchronized (this) {
stepIdleStateLocked();
pw.print("Stepped to: "); pw.println(stateToString(mState));
}
return;
+ } else if ("disable".equals(arg)) {
+ synchronized (this) {
+ if (!mIdleDisabled) {
+ mIdleDisabled = true;
+ becomeActiveLocked("disabled");
+ pw.println("Idle mode disabled");
+ }
+ }
+ return;
+ } else if ("enable".equals(arg)) {
+ synchronized (this) {
+ if (mIdleDisabled) {
+ mIdleDisabled = false;
+ becomeInactiveIfAppropriateLocked();
+ pw.println("Idle mode enabled");
+ }
+ }
+ return;
} else if ("whitelist".equals(arg)) {
i++;
while (i < args.length) {
@@ -853,6 +890,7 @@ public class DeviceIdleController extends SystemService {
}
pw.print(" mSigMotionSensor="); pw.println(mSigMotionSensor);
pw.print(" mCurDisplay="); pw.println(mCurDisplay);
+ pw.print(" mIdleDisabled="); pw.println(mIdleDisabled);
pw.print(" mScreenOn="); pw.println(mScreenOn);
pw.print(" mCharging="); pw.println(mCharging);
pw.print(" mSigMotionActive="); pw.println(mSigMotionActive);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index f790f75..decca16 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -69,6 +69,7 @@ import android.view.WindowManagerPolicy;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import libcore.util.Objects;
@@ -423,6 +424,9 @@ public final class PowerManagerService extends SystemService
// True if we are currently in device idle mode.
private boolean mDeviceIdleMode;
+ // Set of app ids that we will always respect the wake locks for.
+ int[] mDeviceIdleWhitelist = new int[0];
+
// True if theater mode is enabled
private boolean mTheaterModeEnabled;
@@ -758,6 +762,7 @@ public final class PowerManagerService extends SystemService
throw new IllegalArgumentException("Wake lock is already dead.");
}
mWakeLocks.add(wakeLock);
+ setWakeLockDisabledStateLocked(wakeLock);
notifyAcquire = true;
}
@@ -894,7 +899,7 @@ public final class PowerManagerService extends SystemService
}
private void notifyWakeLockAcquiredLocked(WakeLock wakeLock) {
- if (mSystemReady) {
+ if (mSystemReady && !wakeLock.mDisabled) {
wakeLock.mNotifiedAcquired = true;
mNotifier.onWakeLockAcquired(wakeLock.mFlags, wakeLock.mTag, wakeLock.mPackageName,
wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource,
@@ -1388,7 +1393,10 @@ public final class PowerManagerService extends SystemService
final WakeLock wakeLock = mWakeLocks.get(i);
switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.PARTIAL_WAKE_LOCK:
- mWakeLockSummary |= WAKE_LOCK_CPU;
+ if (!wakeLock.mDisabled) {
+ // We only respect this if the wake lock is not disabled.
+ mWakeLockSummary |= WAKE_LOCK_CPU;
+ }
break;
case PowerManager.FULL_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
@@ -2248,12 +2256,12 @@ public final class PowerManagerService extends SystemService
}
}
- private void setStayOnSettingInternal(int val) {
+ void setStayOnSettingInternal(int val) {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.STAY_ON_WHILE_PLUGGED_IN, val);
}
- private void setMaximumScreenOffTimeoutFromDeviceAdminInternal(int timeMs) {
+ void setMaximumScreenOffTimeoutFromDeviceAdminInternal(int timeMs) {
synchronized (mLock) {
mMaximumScreenOffTimeoutFromDeviceAdmin = timeMs;
mDirty |= DIRTY_SETTINGS;
@@ -2261,6 +2269,69 @@ public final class PowerManagerService extends SystemService
}
}
+ void setDeviceIdleModeInternal(boolean enabled) {
+ synchronized (mLock) {
+ if (mDeviceIdleMode != enabled) {
+ mDeviceIdleMode = enabled;
+ updateWakeLockDisabledStatesLocked();
+ }
+ }
+ }
+
+ void setDeviceIdleWhitelistInternal(int[] appids) {
+ synchronized (mLock) {
+ mDeviceIdleWhitelist = appids;
+ if (mDeviceIdleMode) {
+ updateWakeLockDisabledStatesLocked();
+ }
+ }
+ }
+
+ private void updateWakeLockDisabledStatesLocked() {
+ boolean changed = false;
+ final int numWakeLocks = mWakeLocks.size();
+ for (int i = 0; i < numWakeLocks; i++) {
+ final WakeLock wakeLock = mWakeLocks.get(i);
+ if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
+ == PowerManager.PARTIAL_WAKE_LOCK) {
+ if (setWakeLockDisabledStateLocked(wakeLock)) {
+ changed = true;
+ if (wakeLock.mDisabled) {
+ // This wake lock is no longer being respected.
+ notifyWakeLockReleasedLocked(wakeLock);
+ } else {
+ notifyWakeLockAcquiredLocked(wakeLock);
+ }
+ }
+ }
+ }
+ if (changed) {
+ mDirty |= DIRTY_WAKE_LOCKS;
+ updatePowerStateLocked();
+ }
+ }
+
+ private boolean setWakeLockDisabledStateLocked(WakeLock wakeLock) {
+ if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
+ == PowerManager.PARTIAL_WAKE_LOCK) {
+ boolean disabled = false;
+ if (mDeviceIdleMode) {
+ final int appid = UserHandle.getAppId(wakeLock.mOwnerUid);
+ // If we are in idle mode, we will ignore all partial wake locks that are
+ // for application uids that are not whitelisted.
+ if (appid >= Process.FIRST_APPLICATION_UID &&
+ Arrays.binarySearch(mDeviceIdleWhitelist, appid) < 0) {
+ disabled = true;
+ }
+ }
+ if (wakeLock.mDisabled != disabled) {
+ wakeLock.mDisabled = disabled;
+ return true;
+ }
+ }
+ return false;
+ }
+
private boolean isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked() {
return mMaximumScreenOffTimeoutFromDeviceAdmin >= 0
&& mMaximumScreenOffTimeoutFromDeviceAdmin < Integer.MAX_VALUE;
@@ -2459,6 +2530,8 @@ public final class PowerManagerService extends SystemService
pw.println(" mSandmanSummoned=" + mSandmanSummoned);
pw.println(" mLowPowerModeEnabled=" + mLowPowerModeEnabled);
pw.println(" mBatteryLevelLow=" + mBatteryLevelLow);
+ pw.println(" mDeviceIdleMode=" + mDeviceIdleMode);
+ pw.println(" mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist));
pw.println(" mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
pw.println(" mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime));
pw.println(" mLastUserActivityTime=" + TimeUtils.formatUptime(mLastUserActivityTime));
@@ -2671,6 +2744,7 @@ public final class PowerManagerService extends SystemService
public final int mOwnerUid;
public final int mOwnerPid;
public boolean mNotifiedAcquired;
+ public boolean mDisabled;
public WakeLock(IBinder lock, int flags, String tag, String packageName,
WorkSource workSource, String historyTag, int ownerUid, int ownerPid) {
@@ -2729,7 +2803,7 @@ public final class PowerManagerService extends SystemService
@Override
public String toString() {
return getLockLevelString()
- + " '" + mTag + "'" + getLockFlagsString()
+ + " '" + mTag + "'" + getLockFlagsString() + (mDisabled ? " DISABLED" : "")
+ " (uid=" + mOwnerUid + ", pid=" + mOwnerPid + ", ws=" + mWorkSource + ")";
}
@@ -3340,9 +3414,12 @@ public final class PowerManagerService extends SystemService
@Override
public void setDeviceIdleMode(boolean enabled) {
- synchronized (mLock) {
- mDeviceIdleMode = enabled;
- }
+ setDeviceIdleModeInternal(enabled);
+ }
+
+ @Override
+ public void setDeviceIdleWhitelist(int[] appids) {
+ setDeviceIdleWhitelistInternal(appids);
}
}
}