diff options
| author | 2023-11-06 17:28:28 +0000 | |
|---|---|---|
| committer | 2023-11-06 17:49:50 +0000 | |
| commit | 40f718891338faa5836a439a3dcc10035d0701ad (patch) | |
| tree | e7c45612779b169b24071cbb019d47f0165851ad | |
| parent | b1df623732cf5bdd64070c527815d83aae738955 (diff) | |
Avoid repeated/redundant work.
1. Avoid scheduling the idle alarm if the device is already considered
idle.
2. Avoid scheduling the idle alarm again if the currently scheduled
alarm is for the same time.
Bug: 309292340
Test: atest FrameworksMockingServicesTests:DeviceIdlenessTrackerTest
Change-Id: I0cb49041d15e5b2bd880ddc06cb2f1aa95e8c174
2 files changed, 100 insertions, 13 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java index 7dd3d1343379..c142482d2eaf 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java @@ -82,6 +82,10 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id * be a negative value if the device is not in state to be considered idle. */ private long mIdlenessCheckScheduledElapsed = -1; + /** + * Time (in the elapsed realtime timebase) when the device can be considered idle. + */ + private long mIdleStartElapsed = Long.MAX_VALUE; private IdlenessListener mIdleListener; private final UiModeManager.OnProjectionStateChangedListener mOnProjectionStateChangedListener = @@ -191,11 +195,7 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id } mProjectionActive = projectionActive; if (mProjectionActive) { - cancelIdlenessCheck(); - if (mIdle) { - mIdle = false; - mIdleListener.reportNewIdleState(mIdle); - } + exitIdle(); } else { maybeScheduleIdlenessCheck("Projection ended"); } @@ -209,6 +209,7 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id pw.print(" mDockIdle: "); pw.println(mDockIdle); pw.print(" mProjectionActive: "); pw.println(mProjectionActive); pw.print(" mIdlenessCheckScheduledElapsed: "); pw.println(mIdlenessCheckScheduledElapsed); + pw.print(" mIdleStartElapsed: "); pw.println(mIdleStartElapsed); } @Override @@ -270,11 +271,7 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id if (DEBUG) { Slog.v(TAG, "exiting idle"); } - cancelIdlenessCheck(); - if (mIdle) { - mIdle = false; - mIdleListener.reportNewIdleState(mIdle); - } + exitIdle(); break; case Intent.ACTION_SCREEN_OFF: case Intent.ACTION_DREAMING_STARTED: @@ -302,6 +299,12 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id } private void maybeScheduleIdlenessCheck(String reason) { + if (mIdle) { + if (DEBUG) { + Slog.w(TAG, "Already idle. Redundant reason=" + reason); + } + return; + } if ((!mScreenOn || mDockIdle) && !mProjectionActive) { final long nowElapsed = sElapsedRealtimeClock.millis(); final long inactivityThresholdMs = mIsStablePower @@ -319,19 +322,32 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id mIdlenessCheckScheduledElapsed = nowElapsed; } final long when = mIdlenessCheckScheduledElapsed + inactivityThresholdMs; + if (when == mIdleStartElapsed) { + if (DEBUG) { + Slog.i(TAG, "No change to idle start time"); + } + return; + } + mIdleStartElapsed = when; if (DEBUG) { Slog.v(TAG, "Scheduling idle : " + reason + " now:" + nowElapsed - + " checkElapsed=" + mIdlenessCheckScheduledElapsed + " when=" + when); + + " checkElapsed=" + mIdlenessCheckScheduledElapsed + + " when=" + mIdleStartElapsed); } mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, - when, mIdleWindowSlop, "JS idleness", + mIdleStartElapsed, mIdleWindowSlop, "JS idleness", AppSchedulingModuleThread.getExecutor(), mIdleAlarmListener); } } - private void cancelIdlenessCheck() { + private void exitIdle() { mAlarm.cancel(mIdleAlarmListener); mIdlenessCheckScheduledElapsed = -1; + mIdleStartElapsed = Long.MAX_VALUE; + if (mIdle) { + mIdle = false; + mIdleListener.reportNewIdleState(false); + } } private void handleIdleTrigger() { diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/idle/DeviceIdlenessTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/idle/DeviceIdlenessTrackerTest.java index 09935f24cf93..0a56c4541c9e 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/idle/DeviceIdlenessTrackerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/idle/DeviceIdlenessTrackerTest.java @@ -163,6 +163,77 @@ public class DeviceIdlenessTrackerTest { } @Test + public void testAlarmSkippedIfAlreadyIdle() { + setDeviceConfigLong(KEY_INACTIVITY_IDLE_THRESHOLD_MS, MINUTE_IN_MILLIS); + setDeviceConfigLong(KEY_INACTIVITY_STABLE_POWER_IDLE_THRESHOLD_MS, 5 * MINUTE_IN_MILLIS); + setBatteryState(false, false); + + Intent dockIdleIntent = new Intent(Intent.ACTION_DOCK_IDLE); + mBroadcastReceiver.onReceive(mContext, dockIdleIntent); + + final long nowElapsed = sElapsedRealtimeClock.millis(); + long expectedAlarmElapsed = nowElapsed + MINUTE_IN_MILLIS; + + ArgumentCaptor<AlarmManager.OnAlarmListener> onAlarmListenerCaptor = + ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class); + + InOrder inOrder = inOrder(mAlarmManager); + inOrder.verify(mAlarmManager) + .setWindow(anyInt(), eq(expectedAlarmElapsed), anyLong(), anyString(), + eq(AppSchedulingModuleThread.getExecutor()), + onAlarmListenerCaptor.capture()); + + AlarmManager.OnAlarmListener onAlarmListener = onAlarmListenerCaptor.getValue(); + + advanceElapsedClock(MINUTE_IN_MILLIS); + + onAlarmListener.onAlarm(); + + // Now in idle. + + // Trigger SCREEN_OFF. Make sure alarm isn't set again. + Intent screenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF); + mBroadcastReceiver.onReceive(mContext, screenOffIntent); + + inOrder.verify(mAlarmManager, never()) + .setWindow(anyInt(), anyLong(), anyLong(), anyString(), + eq(AppSchedulingModuleThread.getExecutor()), any()); + } + + @Test + public void testAlarmSkippedIfNoThresholdChange() { + setDeviceConfigLong(KEY_INACTIVITY_IDLE_THRESHOLD_MS, 10 * MINUTE_IN_MILLIS); + setDeviceConfigLong(KEY_INACTIVITY_STABLE_POWER_IDLE_THRESHOLD_MS, 10 * MINUTE_IN_MILLIS); + setBatteryState(false, false); + + Intent screenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF); + mBroadcastReceiver.onReceive(mContext, screenOffIntent); + + final long nowElapsed = sElapsedRealtimeClock.millis(); + long expectedAlarmElapsed = nowElapsed + 10 * MINUTE_IN_MILLIS; + + InOrder inOrder = inOrder(mAlarmManager); + inOrder.verify(mAlarmManager) + .setWindow(anyInt(), eq(expectedAlarmElapsed), anyLong(), anyString(), + eq(AppSchedulingModuleThread.getExecutor()), any()); + + // Advanced the clock a little to make sure the tracker continues to use the original time. + advanceElapsedClock(MINUTE_IN_MILLIS); + + // Now on stable power. Thresholds are the same, so alarm doesn't need to be rescheduled. + setBatteryState(true, true); + inOrder.verify(mAlarmManager, never()) + .setWindow(anyInt(), eq(expectedAlarmElapsed), anyLong(), anyString(), + eq(AppSchedulingModuleThread.getExecutor()), any()); + + // Not on stable power. Thresholds are the same, so alarm doesn't need to be rescheduled. + setBatteryState(false, false); + inOrder.verify(mAlarmManager, never()) + .setWindow(anyInt(), anyLong(), anyLong(), anyString(), + eq(AppSchedulingModuleThread.getExecutor()), any()); + } + + @Test public void testThresholdChangeWithStablePowerChange() { setDeviceConfigLong(KEY_INACTIVITY_IDLE_THRESHOLD_MS, 10 * MINUTE_IN_MILLIS); setDeviceConfigLong(KEY_INACTIVITY_STABLE_POWER_IDLE_THRESHOLD_MS, 5 * MINUTE_IN_MILLIS); |