Merge "Ensure AlarmManager knows of IDLE state." into udc-dev

This commit is contained in:
Kweku Adams
2023-03-10 19:23:53 +00:00
committed by Android (Google) Code Review
2 changed files with 156 additions and 4 deletions

View File

@@ -2402,7 +2402,6 @@ public class DeviceIdleController extends SystemService
return mConstants;
}
/** Returns the current elapsed realtime in milliseconds. */
long getElapsedRealtime() {
return SystemClock.elapsedRealtime();
@@ -3819,6 +3818,7 @@ public class DeviceIdleController extends SystemService
// Everything is in place to go into IDLE state.
case STATE_IDLE_MAINTENANCE:
moveToStateLocked(STATE_IDLE, reason);
scheduleAlarmLocked(mNextIdleDelay, true);
if (DEBUG) Slog.d(TAG, "Moved to STATE_IDLE. Next alarm in " + mNextIdleDelay +
" ms.");
@@ -3829,7 +3829,6 @@ public class DeviceIdleController extends SystemService
if (mNextIdleDelay < mConstants.IDLE_TIMEOUT) {
mNextIdleDelay = mConstants.IDLE_TIMEOUT;
}
moveToStateLocked(STATE_IDLE, reason);
if (mLightState != LIGHT_STATE_OVERRIDE) {
moveToLightStateLocked(LIGHT_STATE_OVERRIDE, "deep");
cancelLightAlarmLocked();
@@ -3842,6 +3841,7 @@ public class DeviceIdleController extends SystemService
// We have been idling long enough, now it is time to do some work.
mActiveIdleOpCount = 1;
mActiveIdleWakeLock.acquire();
moveToStateLocked(STATE_IDLE_MAINTENANCE, reason);
scheduleAlarmLocked(mNextIdlePendingDelay, false);
if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE to STATE_IDLE_MAINTENANCE. " +
"Next alarm in " + mNextIdlePendingDelay + " ms.");
@@ -3851,7 +3851,6 @@ public class DeviceIdleController extends SystemService
if (mNextIdlePendingDelay < mConstants.IDLE_PENDING_TIMEOUT) {
mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
}
moveToStateLocked(STATE_IDLE_MAINTENANCE, reason);
addEvent(EVENT_DEEP_MAINTENANCE, null);
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
break;

View File

@@ -154,6 +154,7 @@ public class DeviceIdleControllerTest {
ConstraintController constraintController;
// Freeze time for testing.
long nowElapsed;
boolean useMotionSensor = true;
InjectorForTest(Context ctx) {
super(ctx);
@@ -245,7 +246,7 @@ public class DeviceIdleControllerTest {
@Override
boolean useMotionSensor() {
return true;
return useMotionSensor;
}
}
@@ -345,6 +346,12 @@ public class DeviceIdleControllerTest {
mAnyMotionDetector = new AnyMotionDetectorForTest();
mInjector = new InjectorForTest(getContext());
setupDeviceIdleController();
}
private void setupDeviceIdleController() {
reset(mTelephonyManager);
mDeviceIdleController = new DeviceIdleController(getContext(), mInjector);
spyOn(mDeviceIdleController);
doNothing().when(mDeviceIdleController).publishBinderService(any(), any());
@@ -371,6 +378,10 @@ public class DeviceIdleControllerTest {
if (mMockingSession != null) {
mMockingSession.finishMocking();
}
}
@After
public void cleanupDeviceIdleController() {
// DeviceIdleController adds these to LocalServices in the constructor, so we have to remove
// them after each test, otherwise, subsequent tests will fail.
LocalServices.removeServiceForTest(AppStateTracker.class);
@@ -617,6 +628,60 @@ public class DeviceIdleControllerTest {
.scheduleAlarmLocked(eq(mConstants.INACTIVE_TIMEOUT), eq(false));
}
@Test
public void testStateActiveToStateInactive_DoNotUseMotionSensor() {
mInjector.useMotionSensor = false;
cleanupDeviceIdleController();
setupDeviceIdleController();
mDeviceIdleController.becomeActiveLocked("testing", 0);
verifyStateConditions(STATE_ACTIVE);
setAlarmSoon(false);
setChargingOn(false);
setScreenOn(false);
setEmergencyCallActive(false);
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
verifyStateConditions(STATE_INACTIVE);
verify(mDeviceIdleController)
.scheduleAlarmLocked(eq(mConstants.INACTIVE_TIMEOUT), eq(false));
// The device configuration doesn't require a motion sensor to proceed with idling.
// This should be the case on TVs or other such devices. We should set an alarm to move
// forward if the motion sensor is missing in this case.
verify(mAlarmManager).setWindow(
anyInt(), anyLong(), anyLong(),
eq("DeviceIdleController.deep"), any(), any(Handler.class));
}
@Test
public void testStateActiveToStateInactive_MissingMotionSensor() {
mInjector.useMotionSensor = true;
mMotionSensor = null;
cleanupDeviceIdleController();
setupDeviceIdleController();
mDeviceIdleController.becomeActiveLocked("testing", 0);
verifyStateConditions(STATE_ACTIVE);
setAlarmSoon(false);
setChargingOn(false);
setScreenOn(false);
setEmergencyCallActive(false);
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
verifyStateConditions(STATE_INACTIVE);
verify(mDeviceIdleController)
.scheduleAlarmLocked(eq(mConstants.INACTIVE_TIMEOUT), eq(false));
// The device configuration requires a motion sensor to proceed with idling,
// so we should never set an alarm to move forward if the motion sensor is
// missing in this case.
verify(mAlarmManager, never()).setWindow(
anyInt(), anyLong(), anyLong(),
eq("DeviceIdleController.deep"), any(), any(Handler.class));
verify(mAlarmManager, never()).set(
anyInt(), anyLong(),
eq("DeviceIdleController.deep"), any(), any(Handler.class));
}
@Test
public void testStateActiveToStateInactive_UpcomingAlarm() {
final long timeUntilAlarm = mConstants.MIN_TIME_TO_ALARM / 2;
@@ -756,6 +821,94 @@ public class DeviceIdleControllerTest {
verifyStateConditions(STATE_IDLE_MAINTENANCE);
}
@Test
public void testStepIdleStateLocked_ValidStates_MissingMotionSensor() {
mInjector.useMotionSensor = true;
mMotionSensor = null;
cleanupDeviceIdleController();
setupDeviceIdleController();
mInjector.locationManager = mLocationManager;
doReturn(mock(LocationProvider.class)).when(mLocationManager).getProvider(anyString());
// Make sure the controller doesn't think there's a wake-from-idle alarm coming soon.
setAlarmSoon(false);
InOrder alarmManagerInOrder = inOrder(mAlarmManager);
// Set state to INACTIVE.
mDeviceIdleController.becomeActiveLocked("testing", 0);
setChargingOn(false);
setScreenOn(false);
verifyStateConditions(STATE_INACTIVE);
// The device configuration requires a motion sensor to proceed with idling,
// so we should never set an alarm to move forward if the motion sensor is
// missing in this case.
alarmManagerInOrder.verify(mAlarmManager, never())
.setWindow(anyInt(), anyLong(), anyLong(),
eq("DeviceIdleController.deep"), any(), any(Handler.class));
// Pretend that someone is forcing state stepping via adb
mDeviceIdleController.stepIdleStateLocked("testing");
// verifyStateConditions knows this state typically shouldn't happen during normal
// operation, so we can't use it directly here. For this test, all we care about
// is that the state stepped forward.
assertEquals(STATE_IDLE_PENDING, mDeviceIdleController.getState());
// Still no alarm
alarmManagerInOrder.verify(mAlarmManager, never())
.setWindow(anyInt(), anyLong(), anyLong(),
eq("DeviceIdleController.deep"), any(), any(Handler.class));
mDeviceIdleController.stepIdleStateLocked("testing");
// verifyStateConditions knows this state typically shouldn't happen during normal
// operation, so we can't use it directly here. For this test, all we care about
// is that the state stepped forward.
assertEquals(STATE_SENSING, mDeviceIdleController.getState());
// Still no alarm
alarmManagerInOrder.verify(mAlarmManager, never())
.setWindow(anyInt(), anyLong(), anyLong(),
eq("DeviceIdleController.deep"), any(), any(Handler.class));
mDeviceIdleController.stepIdleStateLocked("testing");
// Location manager exists with a provider, so SENSING should go to LOCATING.
// verifyStateConditions knows this state typically shouldn't happen during normal
// operation, so we can't use it directly here. For this test, all we care about
// is that the state stepped forward.
assertEquals(STATE_LOCATING, mDeviceIdleController.getState());
// Still no alarm
alarmManagerInOrder.verify(mAlarmManager, never())
.setWindow(anyInt(), anyLong(), anyLong(),
eq("DeviceIdleController.deep"), any(), any(Handler.class));
mDeviceIdleController.stepIdleStateLocked("testing");
verifyStateConditions(STATE_IDLE);
// The device was forced into IDLE. AlarmManager should be notified.
alarmManagerInOrder.verify(mAlarmManager)
.setIdleUntil(anyInt(), anyLong(),
eq("DeviceIdleController.deep"), any(), any(Handler.class));
// Should just alternate between IDLE and IDLE_MAINTENANCE now. Since we've gotten to this
// point, alarms should be set on each transition.
mDeviceIdleController.stepIdleStateLocked("testing");
verifyStateConditions(STATE_IDLE_MAINTENANCE);
alarmManagerInOrder.verify(mAlarmManager)
.setWindow(anyInt(), anyLong(), anyLong(),
eq("DeviceIdleController.deep"), any(), any(Handler.class));
mDeviceIdleController.stepIdleStateLocked("testing");
verifyStateConditions(STATE_IDLE);
alarmManagerInOrder.verify(mAlarmManager)
.setIdleUntil(anyInt(), anyLong(),
eq("DeviceIdleController.deep"), any(), any(Handler.class));
mDeviceIdleController.stepIdleStateLocked("testing");
verifyStateConditions(STATE_IDLE_MAINTENANCE);
alarmManagerInOrder.verify(mAlarmManager)
.setWindow(anyInt(), anyLong(), anyLong(),
eq("DeviceIdleController.deep"), any(), any(Handler.class));
}
@Test
public void testStepIdleStateLocked_ValidStates_WithWakeFromIdleAlarmSoon() {
enterDeepState(STATE_ACTIVE);