summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Dianne Hackborn <hackbod@google.com> 2015-11-19 18:48:46 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2015-11-19 18:48:46 +0000
commit77fa236e910fd0d330e5c727472c0a31188f830c (patch)
treefda5f93b482659073a6ded16e48a7af81ba25772
parentb9e2803384b048087c02df7b87dc7a6521b05343 (diff)
parent8ed2b97b9e8b8aa34026aa5e9e614494af3d12f6 (diff)
Merge "Implement flexible light idle maintenance windows."
-rw-r--r--services/core/java/com/android/server/DeviceIdleController.java131
1 files changed, 122 insertions, 9 deletions
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 485e26b7752a..f5ed83ed5f1d 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -107,6 +107,8 @@ public class DeviceIdleController extends SystemService
private static final boolean COMPRESS_TIME = false;
+ private static final int EVENT_BUFFER_SIZE = 40;
+
private static final String ACTION_STEP_IDLE_STATE =
"com.android.server.device_idle.STEP_IDLE_STATE";
@@ -196,6 +198,8 @@ public class DeviceIdleController extends SystemService
private long mNextIdlePendingDelay;
private long mNextIdleDelay;
private long mNextLightAlarmTime;
+ private long mCurIdleBudget;
+ private long mMaintenanceStartTime;
private int mActiveIdleOpCount;
private IBinder mDownloadServiceActive;
@@ -274,6 +278,25 @@ public class DeviceIdleController extends SystemService
*/
private int[] mTempWhitelistAppIdArray = new int[0];
+ private static final int EVENT_NULL = 0;
+ private static final int EVENT_NORMAL = 1;
+ private static final int EVENT_LIGHT_IDLE = 2;
+ private static final int EVENT_LIGHT_MAINTENANCE = 3;
+ private static final int EVENT_FULL_IDLE = 4;
+ private static final int EVENT_FULL_MAINTENANCE = 5;
+
+ private int[] mEventCmds = new int[EVENT_BUFFER_SIZE];
+ private long[] mEventTimes = new long[EVENT_BUFFER_SIZE];
+
+ private void addEvent(int cmd) {
+ if (mEventCmds[0] != cmd) {
+ System.arraycopy(mEventCmds, 0, mEventCmds, 1, EVENT_BUFFER_SIZE - 1);
+ System.arraycopy(mEventTimes, 0, mEventTimes, 1, EVENT_BUFFER_SIZE - 1);
+ mEventCmds[0] = cmd;
+ mEventTimes[0] = SystemClock.elapsedRealtime();
+ }
+ }
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
@@ -424,7 +447,10 @@ public class DeviceIdleController extends SystemService
private final class Constants extends ContentObserver {
// Key names stored in the settings value.
private static final String KEY_LIGHT_IDLE_TIMEOUT = "light_idle_to";
- private static final String KEY_LIGHT_IDLE_PENDING_TIMEOUT = "light_idle_pending_to";
+ private static final String KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET
+ = "light_idle_maintenance_min_budget";
+ private static final String KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET
+ = "light_idle_maintenance_max_budget";
private static final String KEY_INACTIVE_TIMEOUT = "inactive_to";
private static final String KEY_SENSING_TIMEOUT = "sensing_to";
private static final String KEY_LOCATING_TIMEOUT = "locating_to";
@@ -454,12 +480,24 @@ public class DeviceIdleController extends SystemService
public long LIGHT_IDLE_TIMEOUT;
/**
- * This is the initial time, after light idle idle, that we will will sit in the
- * LIGHT_IDLE_MAINTENANCE period for the system to run normally before returning to idle.
+ * This is the minimum amount of time we want to make available for maintenance mode
+ * when lightly idling. That is, we will always have at least this amount of time
+ * available maintenance before timing out and cutting off maintenance mode.
* @see Settings.Global#DEVICE_IDLE_CONSTANTS
- * @see #KEY_LIGHT_IDLE_PENDING_TIMEOUT
+ * @see #KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET
*/
- public long LIGHT_IDLE_PENDING_TIMEOUT;
+ public long LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
+
+ /**
+ * This is the maximum amount of time we want to make available for maintenance mode
+ * when lightly idling. That is, if the system isn't using up its minimum maintenance
+ * budget and this time is being added to the budget reserve, this is the maximum
+ * reserve size we will allow to grow and thus the maximum amount of time we will
+ * allow for the maintenance window.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET
+ */
+ public long LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
/**
* This is the time, after becoming inactive, at which we start looking at the
@@ -619,8 +657,12 @@ public class DeviceIdleController extends SystemService
LIGHT_IDLE_TIMEOUT = mParser.getLong(KEY_LIGHT_IDLE_TIMEOUT,
!COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L);
- LIGHT_IDLE_PENDING_TIMEOUT = mParser.getLong(KEY_LIGHT_IDLE_PENDING_TIMEOUT,
+ LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = mParser.getLong(
+ KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET,
!COMPRESS_TIME ? 1 * 60 * 1000L : 15 * 1000L);
+ LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = mParser.getLong(
+ KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET,
+ !COMPRESS_TIME ? 5 * 60 * 1000L : 30 * 1000L);
INACTIVE_TIMEOUT = mParser.getLong(KEY_INACTIVE_TIMEOUT,
!COMPRESS_TIME ? 30 * 60 * 1000L : 3 * 60 * 1000L);
SENSING_TIMEOUT = mParser.getLong(KEY_SENSING_TIMEOUT,
@@ -662,8 +704,12 @@ public class DeviceIdleController extends SystemService
TimeUtils.formatDuration(LIGHT_IDLE_TIMEOUT, pw);
pw.println();
- pw.print(" "); pw.print(KEY_LIGHT_IDLE_PENDING_TIMEOUT); pw.print("=");
- TimeUtils.formatDuration(LIGHT_IDLE_PENDING_TIMEOUT, pw);
+ pw.print(" "); pw.print(KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET); pw.print("=");
+ TimeUtils.formatDuration(LIGHT_IDLE_MAINTENANCE_MIN_BUDGET, pw);
+ pw.println();
+
+ pw.print(" "); pw.print(KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET); pw.print("=");
+ TimeUtils.formatDuration(LIGHT_IDLE_MAINTENANCE_MAX_BUDGET, pw);
pw.println();
pw.print(" "); pw.print(KEY_INACTIVE_TIMEOUT); pw.print("=");
@@ -1435,8 +1481,11 @@ public class DeviceIdleController extends SystemService
mState = STATE_ACTIVE;
mLightState = LIGHT_STATE_ACTIVE;
mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
+ mCurIdleBudget = 0;
+ mMaintenanceStartTime = 0;
resetIdleManagementLocked();
resetLightIdleManagementLocked();
+ addEvent(EVENT_NORMAL);
}
}
@@ -1496,21 +1545,43 @@ public class DeviceIdleController extends SystemService
switch (mLightState) {
case LIGHT_STATE_INACTIVE:
+ mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
+ mMaintenanceStartTime = 0;
case LIGHT_STATE_IDLE_MAINTENANCE:
+ if (mMaintenanceStartTime != 0) {
+ long duration = SystemClock.elapsedRealtime() - mMaintenanceStartTime;
+ if (duration < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
+ // We didn't use up all of our minimum budget; add this to the reserve.
+ mCurIdleBudget += (mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET-duration);
+ } else {
+ // We used more than our minimum budget; this comes out of the reserve.
+ mCurIdleBudget -= (duration-mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET);
+ }
+ }
+ mMaintenanceStartTime = 0;
scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_TIMEOUT);
if (DEBUG) Slog.d(TAG, "Moved to LIGHT_STATE_IDLE.");
mLightState = LIGHT_STATE_IDLE;
EventLogTags.writeDeviceIdleLight(mLightState, reason);
+ addEvent(EVENT_LIGHT_IDLE);
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON_LIGHT);
break;
case LIGHT_STATE_IDLE:
// We have been idling long enough, now it is time to do some work.
mActiveIdleOpCount = 1;
- scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_PENDING_TIMEOUT);
+ mMaintenanceStartTime = SystemClock.elapsedRealtime();
+ if (mCurIdleBudget < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
+ mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
+ } else if (mCurIdleBudget > mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET) {
+ mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
+ }
+ mMaintenanceStartTime = SystemClock.elapsedRealtime();
+ scheduleLightAlarmLocked(mCurIdleBudget);
if (DEBUG) Slog.d(TAG,
"Moved from LIGHT_STATE_IDLE to LIGHT_STATE_IDLE_MAINTENANCE.");
mLightState = LIGHT_STATE_IDLE_MAINTENANCE;
EventLogTags.writeDeviceIdleLight(mLightState, reason);
+ addEvent(EVENT_LIGHT_MAINTENANCE);
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
break;
}
@@ -1600,6 +1671,7 @@ public class DeviceIdleController extends SystemService
cancelLightAlarmLocked();
}
EventLogTags.writeDeviceIdle(mState, reason);
+ addEvent(EVENT_FULL_IDLE);
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);
break;
case STATE_IDLE:
@@ -1612,6 +1684,7 @@ public class DeviceIdleController extends SystemService
(long)(mNextIdlePendingDelay * mConstants.IDLE_PENDING_FACTOR));
mState = STATE_IDLE_MAINTENANCE;
EventLogTags.writeDeviceIdle(mState, reason);
+ addEvent(EVENT_FULL_MAINTENANCE);
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
break;
}
@@ -1709,7 +1782,10 @@ public class DeviceIdleController extends SystemService
scheduleReportActiveLocked(type, Process.myUid());
mState = STATE_ACTIVE;
mInactiveTimeout = timeout;
+ mCurIdleBudget = 0;
+ mMaintenanceStartTime = 0;
EventLogTags.writeDeviceIdle(mState, type);
+ addEvent(EVENT_NORMAL);
becomeInactive = true;
}
if (mLightState == LIGHT_STATE_OVERRIDE) {
@@ -2016,6 +2092,8 @@ public class DeviceIdleController extends SystemService
pw.println(" Print this help text.");
pw.println(" step");
pw.println(" Immediately step to next state, without waiting for alarm.");
+ pw.println(" light-step");
+ pw.println(" Immediately step to next light idle state, without waiting for alarm.");
pw.println(" force-idle");
pw.println(" Force directly into idle mode, regardless of other device state.");
pw.println(" Use \"step\" to get out.");
@@ -2262,6 +2340,31 @@ public class DeviceIdleController extends SystemService
synchronized (this) {
mConstants.dump(pw);
+ if (mEventCmds[0] != EVENT_NULL) {
+ pw.println(" Idling history:");
+ long now = SystemClock.elapsedRealtime();
+ for (int i=EVENT_BUFFER_SIZE-1; i>=0; i--) {
+ int cmd = mEventCmds[i];
+ if (cmd == EVENT_NULL) {
+ continue;
+ }
+ String label;
+ switch (mEventCmds[i]) {
+ case EVENT_NORMAL: label = " normal"; break;
+ case EVENT_LIGHT_IDLE: label = " light-idle"; break;
+ case EVENT_LIGHT_MAINTENANCE: label = "light-maint"; break;
+ case EVENT_FULL_IDLE: label = " full-idle"; break;
+ case EVENT_FULL_MAINTENANCE: label = " full-maint"; break;
+ default: label = " ??"; break;
+ }
+ pw.print(" ");
+ pw.print(label);
+ pw.print(": ");
+ TimeUtils.formatDuration(mEventTimes[i], now, pw);;
+ pw.println();
+ }
+ }
+
int size = mPowerSaveWhitelistAppsExceptIdle.size();
if (size > 0) {
pw.println(" Whitelist (except idle) system apps:");
@@ -2373,6 +2476,16 @@ public class DeviceIdleController extends SystemService
TimeUtils.formatDuration(mNextLightAlarmTime, SystemClock.elapsedRealtime(), pw);
pw.println();
}
+ if (mCurIdleBudget != 0) {
+ pw.print(" mCurIdleBudget=");
+ TimeUtils.formatDuration(mCurIdleBudget, pw);
+ pw.println();
+ }
+ if (mMaintenanceStartTime != 0) {
+ pw.print(" mMaintenanceStartTime=");
+ TimeUtils.formatDuration(mMaintenanceStartTime, SystemClock.elapsedRealtime(), pw);
+ pw.println();
+ }
if (mSyncActive) {
pw.print(" mSyncActive="); pw.println(mSyncActive);
}