Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 40f71889 authored by Kweku Adams's avatar Kweku Adams
Browse files

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
parent b1df6237
Loading
Loading
Loading
Loading
+29 −13
Original line number Diff line number Diff line
@@ -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() {
+71 −0
Original line number Diff line number Diff line
@@ -162,6 +162,77 @@ public class DeviceIdlenessTrackerTest {
        mDeviceIdlenessTracker.processConstant(mDeviceConfigPropertiesBuilder.build(), key);
    }

    @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);