Loading services/core/java/com/android/server/DeviceIdleController.java +39 −7 Original line number Diff line number Diff line Loading @@ -1742,6 +1742,12 @@ public class DeviceIdleController extends SystemService return mConstants; } /** Returns the current elapsed realtime in milliseconds. */ long getElapsedRealtime() { return SystemClock.elapsedRealtime(); } LocationManager getLocationManager() { if (mLocationManager == null) { mLocationManager = mContext.getSystemService(LocationManager.class); Loading Loading @@ -2023,7 +2029,7 @@ public class DeviceIdleController extends SystemService private void unregisterDeviceIdleConstraintInternal(IDeviceIdleConstraint constraint) { synchronized (this) { // Artifically force the constraint to inactive to unblock anything waiting for it. // Artificially force the constraint to inactive to unblock anything waiting for it. onConstraintStateChangedLocked(constraint, /* active= */ false); // Let the constraint know that we are not listening to it any more. Loading Loading @@ -2746,9 +2752,18 @@ public class DeviceIdleController extends SystemService mState = STATE_QUICK_DOZE_DELAY; // Make sure any motion sensing or locating is stopped. resetIdleManagementLocked(); if (isUpcomingAlarmClock()) { // If there's an upcoming AlarmClock alarm, we won't go into idle, so // setting a wakeup alarm before the upcoming alarm is futile. Set the quick // doze alarm to after the upcoming AlarmClock alarm. scheduleAlarmLocked( mAlarmManager.getNextWakeFromIdleTime() - mInjector.getElapsedRealtime() + mConstants.QUICK_DOZE_DELAY_TIMEOUT, false); } else { // Wait a small amount of time in case something (eg: background service from // recently closed app) needs to finish running. scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false); } EventLogTags.writeDeviceIdle(mState, "no activity"); } else if (mState == STATE_ACTIVE) { mState = STATE_INACTIVE; Loading @@ -2758,7 +2773,16 @@ public class DeviceIdleController extends SystemService if (shouldUseIdleTimeoutFactorLocked()) { delay = (long) (mPreIdleFactor * delay); } if (isUpcomingAlarmClock()) { // If there's an upcoming AlarmClock alarm, we won't go into idle, so // setting a wakeup alarm before the upcoming alarm is futile. Set the idle // alarm to after the upcoming AlarmClock alarm. scheduleAlarmLocked( mAlarmManager.getNextWakeFromIdleTime() - mInjector.getElapsedRealtime() + delay, false); } else { scheduleAlarmLocked(delay, false); } EventLogTags.writeDeviceIdle(mState, "no activity"); } } Loading Loading @@ -2906,13 +2930,21 @@ public class DeviceIdleController extends SystemService return mState; } /** * Returns true if there's an upcoming AlarmClock alarm that is soon enough to prevent the * device from going into idle. */ private boolean isUpcomingAlarmClock() { return mInjector.getElapsedRealtime() + mConstants.MIN_TIME_TO_ALARM >= mAlarmManager.getNextWakeFromIdleTime(); } @VisibleForTesting void stepIdleStateLocked(String reason) { if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState); EventLogTags.writeDeviceIdleStep(); final long now = SystemClock.elapsedRealtime(); if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) { if (isUpcomingAlarmClock()) { // Whoops, there is an upcoming alarm. We don't actually want to go idle. if (mState != STATE_ACTIVE) { mActiveReason = ACTIVE_REASON_ALARM; Loading services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java +68 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.longThat; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; Loading Loading @@ -129,9 +130,12 @@ public class DeviceIdleControllerTest { ConnectivityService connectivityService; LocationManager locationManager; ConstraintController constraintController; // Freeze time for testing. long nowElapsed; InjectorForTest(Context ctx) { super(ctx); nowElapsed = SystemClock.elapsedRealtime(); } @Override Loading @@ -155,6 +159,11 @@ public class DeviceIdleControllerTest { return connectivityService; } @Override long getElapsedRealtime() { return nowElapsed; } @Override LocationManager getLocationManager() { return locationManager; Loading Loading @@ -494,11 +503,44 @@ public class DeviceIdleControllerTest { mDeviceIdleController.becomeActiveLocked("testing", 0); verifyStateConditions(STATE_ACTIVE); setAlarmSoon(false); setChargingOn(false); setScreenOn(false); mDeviceIdleController.becomeInactiveIfAppropriateLocked(); verifyStateConditions(STATE_INACTIVE); verify(mDeviceIdleController) .scheduleAlarmLocked(eq(mConstants.INACTIVE_TIMEOUT), eq(false)); } @Test public void testStateActiveToStateInactive_UpcomingAlarm() { final long timeUntilAlarm = mConstants.MIN_TIME_TO_ALARM / 2; // Set an upcoming alarm that will prevent full idle. doReturn(mInjector.getElapsedRealtime() + timeUntilAlarm) .when(mAlarmManager).getNextWakeFromIdleTime(); InOrder inOrder = inOrder(mDeviceIdleController); enterDeepState(STATE_ACTIVE); setQuickDozeEnabled(false); setChargingOn(false); setScreenOn(false); mDeviceIdleController.becomeInactiveIfAppropriateLocked(); verifyStateConditions(STATE_INACTIVE); inOrder.verify(mDeviceIdleController) .scheduleAlarmLocked(eq(timeUntilAlarm + mConstants.INACTIVE_TIMEOUT), eq(false)); enterDeepState(STATE_ACTIVE); setQuickDozeEnabled(true); setChargingOn(false); setScreenOn(false); mDeviceIdleController.becomeInactiveIfAppropriateLocked(); verifyStateConditions(STATE_QUICK_DOZE_DELAY); inOrder.verify(mDeviceIdleController).scheduleAlarmLocked( eq(timeUntilAlarm + mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false)); } @Test Loading @@ -515,42 +557,68 @@ public class DeviceIdleControllerTest { @Test public void testTransitionFromAnyStateToStateQuickDozeDelay() { setAlarmSoon(false); InOrder inOrder = inOrder(mDeviceIdleController); enterDeepState(STATE_ACTIVE); setQuickDozeEnabled(true); setChargingOn(false); setScreenOn(false); verifyStateConditions(STATE_QUICK_DOZE_DELAY); inOrder.verify(mDeviceIdleController) .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false)); enterDeepState(STATE_INACTIVE); setQuickDozeEnabled(true); verifyStateConditions(STATE_QUICK_DOZE_DELAY); inOrder.verify(mDeviceIdleController) .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false)); enterDeepState(STATE_IDLE_PENDING); setQuickDozeEnabled(true); verifyStateConditions(STATE_QUICK_DOZE_DELAY); inOrder.verify(mDeviceIdleController) .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false)); enterDeepState(STATE_SENSING); setQuickDozeEnabled(true); verifyStateConditions(STATE_QUICK_DOZE_DELAY); inOrder.verify(mDeviceIdleController) .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false)); enterDeepState(STATE_LOCATING); setQuickDozeEnabled(true); verifyStateConditions(STATE_QUICK_DOZE_DELAY); inOrder.verify(mDeviceIdleController) .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false)); // IDLE should stay as IDLE. enterDeepState(STATE_IDLE); // Clear out any alarm setting from the order before checking for this section. inOrder.verify(mDeviceIdleController, atLeastOnce()) .scheduleAlarmLocked(anyLong(), anyBoolean()); setQuickDozeEnabled(true); verifyStateConditions(STATE_IDLE); inOrder.verify(mDeviceIdleController, never()).scheduleAlarmLocked(anyLong(), anyBoolean()); // IDLE_MAINTENANCE should stay as IDLE_MAINTENANCE. enterDeepState(STATE_IDLE_MAINTENANCE); // Clear out any alarm setting from the order before checking for this section. inOrder.verify(mDeviceIdleController, atLeastOnce()) .scheduleAlarmLocked(anyLong(), anyBoolean()); setQuickDozeEnabled(true); verifyStateConditions(STATE_IDLE_MAINTENANCE); inOrder.verify(mDeviceIdleController, never()).scheduleAlarmLocked(anyLong(), anyBoolean()); // State is already QUICK_DOZE_DELAY. No work should be done. enterDeepState(STATE_QUICK_DOZE_DELAY); // Clear out any alarm setting from the order before checking for this section. inOrder.verify(mDeviceIdleController, atLeastOnce()) .scheduleAlarmLocked(anyLong(), anyBoolean()); setQuickDozeEnabled(true); mDeviceIdleController.becomeInactiveIfAppropriateLocked(); verifyStateConditions(STATE_QUICK_DOZE_DELAY); inOrder.verify(mDeviceIdleController, never()).scheduleAlarmLocked(anyLong(), anyBoolean()); } @Test Loading Loading
services/core/java/com/android/server/DeviceIdleController.java +39 −7 Original line number Diff line number Diff line Loading @@ -1742,6 +1742,12 @@ public class DeviceIdleController extends SystemService return mConstants; } /** Returns the current elapsed realtime in milliseconds. */ long getElapsedRealtime() { return SystemClock.elapsedRealtime(); } LocationManager getLocationManager() { if (mLocationManager == null) { mLocationManager = mContext.getSystemService(LocationManager.class); Loading Loading @@ -2023,7 +2029,7 @@ public class DeviceIdleController extends SystemService private void unregisterDeviceIdleConstraintInternal(IDeviceIdleConstraint constraint) { synchronized (this) { // Artifically force the constraint to inactive to unblock anything waiting for it. // Artificially force the constraint to inactive to unblock anything waiting for it. onConstraintStateChangedLocked(constraint, /* active= */ false); // Let the constraint know that we are not listening to it any more. Loading Loading @@ -2746,9 +2752,18 @@ public class DeviceIdleController extends SystemService mState = STATE_QUICK_DOZE_DELAY; // Make sure any motion sensing or locating is stopped. resetIdleManagementLocked(); if (isUpcomingAlarmClock()) { // If there's an upcoming AlarmClock alarm, we won't go into idle, so // setting a wakeup alarm before the upcoming alarm is futile. Set the quick // doze alarm to after the upcoming AlarmClock alarm. scheduleAlarmLocked( mAlarmManager.getNextWakeFromIdleTime() - mInjector.getElapsedRealtime() + mConstants.QUICK_DOZE_DELAY_TIMEOUT, false); } else { // Wait a small amount of time in case something (eg: background service from // recently closed app) needs to finish running. scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false); } EventLogTags.writeDeviceIdle(mState, "no activity"); } else if (mState == STATE_ACTIVE) { mState = STATE_INACTIVE; Loading @@ -2758,7 +2773,16 @@ public class DeviceIdleController extends SystemService if (shouldUseIdleTimeoutFactorLocked()) { delay = (long) (mPreIdleFactor * delay); } if (isUpcomingAlarmClock()) { // If there's an upcoming AlarmClock alarm, we won't go into idle, so // setting a wakeup alarm before the upcoming alarm is futile. Set the idle // alarm to after the upcoming AlarmClock alarm. scheduleAlarmLocked( mAlarmManager.getNextWakeFromIdleTime() - mInjector.getElapsedRealtime() + delay, false); } else { scheduleAlarmLocked(delay, false); } EventLogTags.writeDeviceIdle(mState, "no activity"); } } Loading Loading @@ -2906,13 +2930,21 @@ public class DeviceIdleController extends SystemService return mState; } /** * Returns true if there's an upcoming AlarmClock alarm that is soon enough to prevent the * device from going into idle. */ private boolean isUpcomingAlarmClock() { return mInjector.getElapsedRealtime() + mConstants.MIN_TIME_TO_ALARM >= mAlarmManager.getNextWakeFromIdleTime(); } @VisibleForTesting void stepIdleStateLocked(String reason) { if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState); EventLogTags.writeDeviceIdleStep(); final long now = SystemClock.elapsedRealtime(); if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) { if (isUpcomingAlarmClock()) { // Whoops, there is an upcoming alarm. We don't actually want to go idle. if (mState != STATE_ACTIVE) { mActiveReason = ACTIVE_REASON_ALARM; Loading
services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java +68 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.longThat; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; Loading Loading @@ -129,9 +130,12 @@ public class DeviceIdleControllerTest { ConnectivityService connectivityService; LocationManager locationManager; ConstraintController constraintController; // Freeze time for testing. long nowElapsed; InjectorForTest(Context ctx) { super(ctx); nowElapsed = SystemClock.elapsedRealtime(); } @Override Loading @@ -155,6 +159,11 @@ public class DeviceIdleControllerTest { return connectivityService; } @Override long getElapsedRealtime() { return nowElapsed; } @Override LocationManager getLocationManager() { return locationManager; Loading Loading @@ -494,11 +503,44 @@ public class DeviceIdleControllerTest { mDeviceIdleController.becomeActiveLocked("testing", 0); verifyStateConditions(STATE_ACTIVE); setAlarmSoon(false); setChargingOn(false); setScreenOn(false); mDeviceIdleController.becomeInactiveIfAppropriateLocked(); verifyStateConditions(STATE_INACTIVE); verify(mDeviceIdleController) .scheduleAlarmLocked(eq(mConstants.INACTIVE_TIMEOUT), eq(false)); } @Test public void testStateActiveToStateInactive_UpcomingAlarm() { final long timeUntilAlarm = mConstants.MIN_TIME_TO_ALARM / 2; // Set an upcoming alarm that will prevent full idle. doReturn(mInjector.getElapsedRealtime() + timeUntilAlarm) .when(mAlarmManager).getNextWakeFromIdleTime(); InOrder inOrder = inOrder(mDeviceIdleController); enterDeepState(STATE_ACTIVE); setQuickDozeEnabled(false); setChargingOn(false); setScreenOn(false); mDeviceIdleController.becomeInactiveIfAppropriateLocked(); verifyStateConditions(STATE_INACTIVE); inOrder.verify(mDeviceIdleController) .scheduleAlarmLocked(eq(timeUntilAlarm + mConstants.INACTIVE_TIMEOUT), eq(false)); enterDeepState(STATE_ACTIVE); setQuickDozeEnabled(true); setChargingOn(false); setScreenOn(false); mDeviceIdleController.becomeInactiveIfAppropriateLocked(); verifyStateConditions(STATE_QUICK_DOZE_DELAY); inOrder.verify(mDeviceIdleController).scheduleAlarmLocked( eq(timeUntilAlarm + mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false)); } @Test Loading @@ -515,42 +557,68 @@ public class DeviceIdleControllerTest { @Test public void testTransitionFromAnyStateToStateQuickDozeDelay() { setAlarmSoon(false); InOrder inOrder = inOrder(mDeviceIdleController); enterDeepState(STATE_ACTIVE); setQuickDozeEnabled(true); setChargingOn(false); setScreenOn(false); verifyStateConditions(STATE_QUICK_DOZE_DELAY); inOrder.verify(mDeviceIdleController) .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false)); enterDeepState(STATE_INACTIVE); setQuickDozeEnabled(true); verifyStateConditions(STATE_QUICK_DOZE_DELAY); inOrder.verify(mDeviceIdleController) .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false)); enterDeepState(STATE_IDLE_PENDING); setQuickDozeEnabled(true); verifyStateConditions(STATE_QUICK_DOZE_DELAY); inOrder.verify(mDeviceIdleController) .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false)); enterDeepState(STATE_SENSING); setQuickDozeEnabled(true); verifyStateConditions(STATE_QUICK_DOZE_DELAY); inOrder.verify(mDeviceIdleController) .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false)); enterDeepState(STATE_LOCATING); setQuickDozeEnabled(true); verifyStateConditions(STATE_QUICK_DOZE_DELAY); inOrder.verify(mDeviceIdleController) .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false)); // IDLE should stay as IDLE. enterDeepState(STATE_IDLE); // Clear out any alarm setting from the order before checking for this section. inOrder.verify(mDeviceIdleController, atLeastOnce()) .scheduleAlarmLocked(anyLong(), anyBoolean()); setQuickDozeEnabled(true); verifyStateConditions(STATE_IDLE); inOrder.verify(mDeviceIdleController, never()).scheduleAlarmLocked(anyLong(), anyBoolean()); // IDLE_MAINTENANCE should stay as IDLE_MAINTENANCE. enterDeepState(STATE_IDLE_MAINTENANCE); // Clear out any alarm setting from the order before checking for this section. inOrder.verify(mDeviceIdleController, atLeastOnce()) .scheduleAlarmLocked(anyLong(), anyBoolean()); setQuickDozeEnabled(true); verifyStateConditions(STATE_IDLE_MAINTENANCE); inOrder.verify(mDeviceIdleController, never()).scheduleAlarmLocked(anyLong(), anyBoolean()); // State is already QUICK_DOZE_DELAY. No work should be done. enterDeepState(STATE_QUICK_DOZE_DELAY); // Clear out any alarm setting from the order before checking for this section. inOrder.verify(mDeviceIdleController, atLeastOnce()) .scheduleAlarmLocked(anyLong(), anyBoolean()); setQuickDozeEnabled(true); mDeviceIdleController.becomeInactiveIfAppropriateLocked(); verifyStateConditions(STATE_QUICK_DOZE_DELAY); inOrder.verify(mDeviceIdleController, never()).scheduleAlarmLocked(anyLong(), anyBoolean()); } @Test Loading