am 9c8600e1: Merge "Implement device idle in power manager." into mnc-dev

* commit '9c8600e1af1af6eb2f57a965bbfe941fbd082786':
  Implement device idle in power manager.
This commit is contained in:
Dianne Hackborn
2015-05-11 22:26:33 +00:00
committed by Android Git Automerger
6 changed files with 225 additions and 21 deletions

View File

@@ -3761,7 +3761,9 @@ package android.app {
method public android.app.AlarmManager.AlarmClockInfo getNextAlarmClock();
method public void set(int, long, android.app.PendingIntent);
method public void setAlarmClock(android.app.AlarmManager.AlarmClockInfo, android.app.PendingIntent);
method public void setAndAllowWhileIdle(int, long, android.app.PendingIntent);
method public void setExact(int, long, android.app.PendingIntent);
method public void setExactAndAllowWhileIdle(int, long, android.app.PendingIntent);
method public void setInexactRepeating(int, long, long, android.app.PendingIntent);
method public void setRepeating(int, long, long, android.app.PendingIntent);
method public void setTime(long);

View File

@@ -3851,7 +3851,9 @@ package android.app {
method public void set(int, long, android.app.PendingIntent);
method public void set(int, long, long, long, android.app.PendingIntent, android.os.WorkSource);
method public void setAlarmClock(android.app.AlarmManager.AlarmClockInfo, android.app.PendingIntent);
method public void setAndAllowWhileIdle(int, long, android.app.PendingIntent);
method public void setExact(int, long, android.app.PendingIntent);
method public void setExactAndAllowWhileIdle(int, long, android.app.PendingIntent);
method public void setInexactRepeating(int, long, long, android.app.PendingIntent);
method public void setRepeating(int, long, long, android.app.PendingIntent);
method public void setTime(long);

View File

@@ -71,10 +71,7 @@ import java.io.IOException;
* {@link android.content.Context#getSystemService
* Context.getSystemService(Context.ALARM_SERVICE)}.
*/
public class AlarmManager
{
private static final String TAG = "AlarmManager";
public class AlarmManager {
/**
* Alarm time in {@link System#currentTimeMillis System.currentTimeMillis()}
* (wall clock time in UTC), which will wake up the device when
@@ -558,7 +555,93 @@ public class AlarmManager
long intervalMillis, PendingIntent operation) {
setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, intervalMillis, 0, operation, null, null);
}
/**
* Like {@link #set(int, long, PendingIntent)}, but this alarm will be allowed to execute
* even when the system is in low-power idle modes. This type of alarm must <b>only</b>
* be used for situations where it is actually required that the alarm go off while in
* idle -- a reasonable example would be for a calendar notification that should make a
* sound so the user is aware of it. These alarms can significantly impact the power use
* of the device when idle (and thus cause significant battery blame to the app scheduling
* them), so they should be used with care.
*
* <p>Unlike other alarms, the system is free to reschedule this type of alarm to happen
* out of order with any other alarms, even those from the same app. This will clearly happen
* when the device is idle (since this alarm can go off while idle, when any other alarms
* from the app will be held until later), but may also happen even when not idle.</p>
*
* <p>Regardless of the app's target SDK version, this call always allows batching of the
* alarm.</p>
*
* @param type One of {@link #ELAPSED_REALTIME}, {@link #ELAPSED_REALTIME_WAKEUP},
* {@link #RTC}, or {@link #RTC_WAKEUP}.
* @param triggerAtMillis time in milliseconds that the alarm should go
* off, using the appropriate clock (depending on the alarm type).
* @param operation Action to perform when the alarm goes off;
* typically comes from {@link PendingIntent#getBroadcast
* IntentSender.getBroadcast()}.
*
* @see #set(int, long, PendingIntent)
* @see #setExactAndAllowWhileIdle
* @see #cancel
* @see android.content.Context#sendBroadcast
* @see android.content.Context#registerReceiver
* @see android.content.Intent#filterEquals
* @see #ELAPSED_REALTIME
* @see #ELAPSED_REALTIME_WAKEUP
* @see #RTC
* @see #RTC_WAKEUP
*/
public void setAndAllowWhileIdle(int type, long triggerAtMillis, PendingIntent operation) {
setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, 0, FLAG_ALLOW_WHILE_IDLE, operation,
null, null);
}
/**
* Like {@link #setExact(int, long, PendingIntent)}, but this alarm will be allowed to execute
* even when the system is in low-power idle modes. If you don't need exact scheduling of
* the alarm but still need to execute while idle, consider using
* {@link #setAndAllowWhileIdle}. This type of alarm must <b>only</b>
* be used for situations where it is actually required that the alarm go off while in
* idle -- a reasonable example would be for a calendar notification that should make a
* sound so the user is aware of it. These alarms can significantly impact the power use
* of the device when idle (and thus cause significant battery blame to the app scheduling
* them), so they should be used with care.
*
* <p>Unlike other alarms, the system is free to reschedule this type of alarm to happen
* out of order with any other alarms, even those from the same app. This will clearly happen
* when the device is idle (since this alarm can go off while idle, when any other alarms
* from the app will be held until later), but may also happen even when not idle.
* Note that the OS will allow itself more flexibility for scheduling these alarms than
* regular exact alarms, since the application has opted into this behavior. When the
* device is idle it may take even more liberties with scheduling in order to optimize
* for battery life.</p>
*
* @param type One of {@link #ELAPSED_REALTIME}, {@link #ELAPSED_REALTIME_WAKEUP},
* {@link #RTC}, or {@link #RTC_WAKEUP}.
* @param triggerAtMillis time in milliseconds that the alarm should go
* off, using the appropriate clock (depending on the alarm type).
* @param operation Action to perform when the alarm goes off;
* typically comes from {@link PendingIntent#getBroadcast
* IntentSender.getBroadcast()}.
*
* @see #set
* @see #setRepeating
* @see #setWindow
* @see #cancel
* @see android.content.Context#sendBroadcast
* @see android.content.Context#registerReceiver
* @see android.content.Intent#filterEquals
* @see #ELAPSED_REALTIME
* @see #ELAPSED_REALTIME_WAKEUP
* @see #RTC
* @see #RTC_WAKEUP
*/
public void setExactAndAllowWhileIdle(int type, long triggerAtMillis, PendingIntent operation) {
setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, FLAG_ALLOW_WHILE_IDLE, operation,
null, null);
}
/**
* Remove any alarms with a matching {@link Intent}.
* Any alarm, of any type, whose Intent matches this one (as defined by

View File

@@ -134,4 +134,6 @@ public abstract class PowerManagerInternal {
}
public abstract void setDeviceIdleMode(boolean enabled);
public abstract void setDeviceIdleWhitelist(int[] appids);
}

View File

@@ -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);

View File

@@ -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);
}
}
}