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:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -134,4 +134,6 @@ public abstract class PowerManagerInternal {
|
||||
}
|
||||
|
||||
public abstract void setDeviceIdleMode(boolean enabled);
|
||||
|
||||
public abstract void setDeviceIdleWhitelist(int[] appids);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user