diff options
author | Dianne Hackborn <hackbod@google.com> | 2015-05-08 17:21:48 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2015-05-11 15:16:47 -0700 |
commit | 8d66b3fbf5d8036e25d64a8472bcd2b6b7892a1a (patch) | |
tree | cc4aa1432f4abecd3b7d34275945a0c1c678fd34 /services | |
parent | cfd6e9dfd063cba795497f251aa6f7fe2554f10b (diff) | |
download | frameworks_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.java | 54 | ||||
-rw-r--r-- | services/core/java/com/android/server/power/PowerManagerService.java | 93 |
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); } } } |