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

Commit 51f86b52 authored by yumeichen's avatar yumeichen
Browse files

Add validation before logging ScreenInteractiveSessionReported

The value of reducedInteractiveStateOnDurationMs should be in [0, screen_off_timeout]. Don't send the log if the value is invalid.

Flag: EXEMPT bugfix
Test: atest WakefulnessSessionObserverTest
Bug: 359355557
Change-Id: I9f8a9a0b1992e0e66f111ae9ee4c53f56563f28e
parent c72efabd
Loading
Loading
Loading
Loading
+51 −52
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayAddress;
@@ -70,12 +71,11 @@ import java.lang.annotation.RetentionPolicy;
public class WakefulnessSessionObserver {
    private static final String TAG = "WakefulnessSessionObserver";

    private static final int OFF_REASON_UNKNOWN = FrameworkStatsLog
    static final int OFF_REASON_UNKNOWN = FrameworkStatsLog
            .SCREEN_INTERACTIVE_SESSION_REPORTED__INTERACTIVE_STATE_OFF_REASON__UNKNOWN;
    private static final int OFF_REASON_TIMEOUT = FrameworkStatsLog
    static final int OFF_REASON_TIMEOUT = FrameworkStatsLog
            .SCREEN_INTERACTIVE_SESSION_REPORTED__INTERACTIVE_STATE_OFF_REASON__TIMEOUT;
    @VisibleForTesting
    protected static final int OFF_REASON_POWER_BUTTON = FrameworkStatsLog
    static final int OFF_REASON_POWER_BUTTON = FrameworkStatsLog
            .SCREEN_INTERACTIVE_SESSION_REPORTED__INTERACTIVE_STATE_OFF_REASON__POWER_BUTTON;

    /**
@@ -90,25 +90,21 @@ public class WakefulnessSessionObserver {
    @Retention(RetentionPolicy.SOURCE)
    private @interface OffReason {}

    private static final int OVERRIDE_OUTCOME_UNKNOWN = FrameworkStatsLog
    static final int OVERRIDE_OUTCOME_UNKNOWN = FrameworkStatsLog
            .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__UNKNOWN;
    @VisibleForTesting
    protected static final int OVERRIDE_OUTCOME_TIMEOUT_SUCCESS = FrameworkStatsLog
    static final int OVERRIDE_OUTCOME_TIMEOUT_SUCCESS = FrameworkStatsLog
            .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__TIMEOUT_SUCCESS;
    @VisibleForTesting
    protected static final int OVERRIDE_OUTCOME_TIMEOUT_USER_INITIATED_REVERT = FrameworkStatsLog
    static final int OVERRIDE_OUTCOME_TIMEOUT_USER_INITIATED_REVERT = FrameworkStatsLog
            .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__TIMEOUT_USER_INITIATED_REVERT;
    private static final int OVERRIDE_OUTCOME_CANCEL_CLIENT_API_CALL = FrameworkStatsLog
    static final int OVERRIDE_OUTCOME_CANCEL_CLIENT_API_CALL = FrameworkStatsLog
            .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__CANCEL_CLIENT_API_CALL;
    @VisibleForTesting
    protected static final int OVERRIDE_OUTCOME_CANCEL_USER_INTERACTION = FrameworkStatsLog
    static final int OVERRIDE_OUTCOME_CANCEL_USER_INTERACTION = FrameworkStatsLog
            .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__CANCEL_USER_INTERACTION;
    @VisibleForTesting
    protected static final int OVERRIDE_OUTCOME_CANCEL_POWER_BUTTON = FrameworkStatsLog
    static final int OVERRIDE_OUTCOME_CANCEL_POWER_BUTTON = FrameworkStatsLog
            .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__CANCEL_POWER_BUTTON;
    private static final int OVERRIDE_OUTCOME_CANCEL_CLIENT_DISCONNECT = FrameworkStatsLog
    static final int OVERRIDE_OUTCOME_CANCEL_CLIENT_DISCONNECT = FrameworkStatsLog
            .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__CANCEL_CLIENT_DISCONNECTED;
    private static final int OVERRIDE_OUTCOME_CANCEL_OTHER = FrameworkStatsLog
    static final int OVERRIDE_OUTCOME_CANCEL_OTHER = FrameworkStatsLog
            .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__CANCEL_OTHER;

    /**
@@ -128,19 +124,15 @@ public class WakefulnessSessionObserver {
    @Retention(RetentionPolicy.SOURCE)
    private @interface OverrideOutcome {}

    private static final int POLICY_REASON_UNKNOWN = FrameworkStatsLog
    static final int POLICY_REASON_UNKNOWN = FrameworkStatsLog
            .SCREEN_DIM_REPORTED__POLICY_REASON__UNKNOWN;
    @VisibleForTesting
    protected static final int POLICY_REASON_OFF_TIMEOUT = FrameworkStatsLog
    static final int POLICY_REASON_OFF_TIMEOUT = FrameworkStatsLog
            .SCREEN_DIM_REPORTED__POLICY_REASON__OFF_TIMEOUT;
    @VisibleForTesting
    protected static final int POLICY_REASON_OFF_POWER_BUTTON = FrameworkStatsLog
    static final int POLICY_REASON_OFF_POWER_BUTTON = FrameworkStatsLog
            .SCREEN_DIM_REPORTED__POLICY_REASON__OFF_POWER_BUTTON;
    @VisibleForTesting
    protected static final int POLICY_REASON_BRIGHT_UNDIM = FrameworkStatsLog
    static final int POLICY_REASON_BRIGHT_UNDIM = FrameworkStatsLog
            .SCREEN_DIM_REPORTED__POLICY_REASON__BRIGHT_UNDIM;
    @VisibleForTesting
    protected static final int POLICY_REASON_BRIGHT_INITIATED_REVERT = FrameworkStatsLog
    static final int POLICY_REASON_BRIGHT_INITIATED_REVERT = FrameworkStatsLog
            .SCREEN_DIM_REPORTED__POLICY_REASON__BRIGHT_INITIATED_REVERT;

    /**
@@ -157,21 +149,18 @@ public class WakefulnessSessionObserver {
    @Retention(RetentionPolicy.SOURCE)
    private @interface PolicyReason {}

    @VisibleForTesting protected static final int DEFAULT_USER_ACTIVITY = USER_ACTIVITY_EVENT_OTHER;
    private static final long USER_INITIATED_REVERT_THRESHOLD_MILLIS = 5000L;
    private static final long SEND_OVERRIDE_TIMEOUT_LOG_THRESHOLD_MILLIS = 1000L;
    @VisibleForTesting
    protected static final long SCREEN_POLICY_DIM_POWER_OFF_BRIGHT_THRESHOLD_MILLIS = 500L;
    static final int DEFAULT_USER_ACTIVITY = USER_ACTIVITY_EVENT_OTHER;
    static final long USER_INITIATED_REVERT_THRESHOLD_MILLIS = 5000L;
    static final long SEND_OVERRIDE_TIMEOUT_LOG_THRESHOLD_MILLIS = 1000L;
    static final long SCREEN_POLICY_DIM_POWER_OFF_BRIGHT_THRESHOLD_MILLIS = 500L;

    @VisibleForTesting protected static final Object HANDLER_TOKEN = new Object();
    static final Object HANDLER_TOKEN = new Object();

    private Context mContext;
    private int mScreenOffTimeoutMs;
    private int mOverrideTimeoutMs = 0;
    @VisibleForTesting
    protected final SparseArray<WakefulnessSessionPowerGroup> mPowerGroups = new SparseArray<>();
    @VisibleForTesting
    protected WakefulnessSessionFrameworkStatsLogger mWakefulnessSessionFrameworkStatsLogger;
    final SparseArray<WakefulnessSessionPowerGroup> mPowerGroups = new SparseArray<>();
    WakefulnessSessionFrameworkStatsLogger mWakefulnessSessionFrameworkStatsLogger;
    private final Clock mClock;
    private final Object mLock = new Object();
    private final Handler mHandler;
@@ -347,7 +336,8 @@ public class WakefulnessSessionObserver {
        writer.println();
    }

    private void updateSettingScreenOffTimeout(Context context) {
    @VisibleForTesting
    void updateSettingScreenOffTimeout(Context context) {
        synchronized (mLock) {
            mScreenOffTimeoutMs = Settings.System.getIntForUser(
                    context.getContentResolver(),
@@ -453,6 +443,7 @@ public class WakefulnessSessionObserver {
                return;
            }

            final int screenOffTimeoutMs = getScreenOffTimeout();
            mIsInteractive = isInteractive(wakefulness);
            if (mIsInteractive) {
                mInteractiveStateOnStartTimestamp = eventTime;
@@ -466,7 +457,7 @@ public class WakefulnessSessionObserver {
                                mPowerGroupId,
                                OVERRIDE_OUTCOME_TIMEOUT_USER_INITIATED_REVERT,
                                mOverrideTimeoutMs,
                                getScreenOffTimeout());
                                screenOffTimeoutMs);
                        mSendOverrideTimeoutLogTimestamp = eventTime;
                    }
                    mTimeoutOffTimestamp = TIMEOUT_OFF_RESET_TIMESTAMP;
@@ -496,7 +487,7 @@ public class WakefulnessSessionObserver {
                                mPowerGroupId,
                                OVERRIDE_OUTCOME_CANCEL_POWER_BUTTON,
                                mOverrideTimeoutMs,
                                getScreenOffTimeout());
                                screenOffTimeoutMs);
                        mSendOverrideTimeoutLogTimestamp = eventTime;
                        mTimeoutOverrideReleaseReason = RELEASE_REASON_UNKNOWN; // reset the reason
                    }
@@ -514,13 +505,12 @@ public class WakefulnessSessionObserver {
                    // timeout has been done successfully.
                    if (isInOverrideTimeout()) {
                        reducedInteractiveStateOnDurationMs =
                                getScreenOffTimeout() - mOverrideTimeoutMs;

                                screenOffTimeoutMs - mOverrideTimeoutMs;
                        mWakefulnessSessionFrameworkStatsLogger.logTimeoutOverrideEvent(
                                mPowerGroupId,
                                OVERRIDE_OUTCOME_TIMEOUT_SUCCESS,
                                mOverrideTimeoutMs,
                                getScreenOffTimeout());
                                screenOffTimeoutMs);
                        mSendOverrideTimeoutLogTimestamp = eventTime;

                        // Record a timestamp to track if the user initiates to revert from off
@@ -533,6 +523,9 @@ public class WakefulnessSessionObserver {

                long interactiveStateOnDurationMs =
                        eventTime - mInteractiveStateOnStartTimestamp;

                if (reducedInteractiveStateOnDurationMs < screenOffTimeoutMs
                        && reducedInteractiveStateOnDurationMs >= 0) {
                    mWakefulnessSessionFrameworkStatsLogger.logSessionEvent(
                            mPowerGroupId,
                            interactiveStateOffReason,
@@ -540,6 +533,11 @@ public class WakefulnessSessionObserver {
                            lastUserActivity,
                            lastUserActivityDurationMs,
                            reducedInteractiveStateOnDurationMs);
                } else {
                    Slog.w(TAG, "invalid reducedInteractiveStateOnDurationMs: "
                            + reducedInteractiveStateOnDurationMs);
                }

            }
        }

@@ -608,6 +606,7 @@ public class WakefulnessSessionObserver {
                return;
            }

            final int screenOffTimeoutMs = getScreenOffTimeout();
            int dimDurationMs = 0;
            int lastUserActivity = mCurrentUserActivityEvent;
            int lastUserActivityDurationMs = (int) (eventTime - mCurrentUserActivityTimestamp);
@@ -625,7 +624,7 @@ public class WakefulnessSessionObserver {
                            lastUserActivity,
                            lastUserActivityDurationMs,
                            dimDurationMs,
                            mScreenOffTimeoutMs);
                            screenOffTimeoutMs);
                    mPastDimDurationMs = dimDurationMs;
                    return;
                }
@@ -645,7 +644,7 @@ public class WakefulnessSessionObserver {
                                lastUserActivity,
                                lastUserActivityDurationMs,
                                dimDurationMs,
                                mScreenOffTimeoutMs);
                                screenOffTimeoutMs);
                        mHandler.removeCallbacksAndMessages(HANDLER_TOKEN);
                    }

@@ -674,7 +673,7 @@ public class WakefulnessSessionObserver {
                                    savedLastUserActivity,
                                    savedLastUserActivityDurationMs,
                                    savedDimDurationMs,
                                    mScreenOffTimeoutMs);
                                    screenOffTimeoutMs);
                            mPastDimDurationMs = savedDimDurationMs;
                        }, HANDLER_TOKEN, SCREEN_POLICY_DIM_POWER_OFF_BRIGHT_THRESHOLD_MILLIS);
                    }
@@ -692,7 +691,7 @@ public class WakefulnessSessionObserver {
                                lastUserActivity,
                                lastUserActivityDurationMs,
                                mPastDimDurationMs,
                                mScreenOffTimeoutMs);
                                screenOffTimeoutMs);
                    }
                    return;
                }
+115 −4
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import static android.view.Display.DEFAULT_DISPLAY_GROUP;
import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_UNKNOWN;
import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_USER_ACTIVITY_TOUCH;
import static com.android.server.power.WakefulnessSessionObserver.OFF_REASON_POWER_BUTTON;
import static com.android.server.power.WakefulnessSessionObserver.OFF_REASON_TIMEOUT;
import static com.android.server.power.WakefulnessSessionObserver.OVERRIDE_OUTCOME_CANCEL_POWER_BUTTON;
import static com.android.server.power.WakefulnessSessionObserver.OVERRIDE_OUTCOME_CANCEL_USER_INTERACTION;
import static com.android.server.power.WakefulnessSessionObserver.OVERRIDE_OUTCOME_TIMEOUT_SUCCESS;
@@ -40,6 +41,7 @@ import static com.android.server.power.WakefulnessSessionObserver.POLICY_REASON_
import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -90,6 +92,7 @@ public class WakefulnessSessionObserverTest {
            mWakefulnessSessionFrameworkStatsLogger;
    @Mock
    private DisplayManagerInternal mDisplayManagerInternal;
    private MockContentResolver mContentResolver = new MockContentResolver();

    private TestHandler mHandler;
    @Before
@@ -106,10 +109,9 @@ public class WakefulnessSessionObserverTest {
                R.integer.config_screenTimeoutOverride);
        when(mContext.getResources()).thenReturn(res);
        FakeSettingsProvider.clearSettingsProvider();
        MockContentResolver mockContentResolver = new MockContentResolver();
        mockContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
        when(mContext.getContentResolver()).thenReturn(mockContentResolver);
        Settings.System.putIntForUser(mockContentResolver, Settings.System.SCREEN_OFF_TIMEOUT,
        mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
        when(mContext.getContentResolver()).thenReturn(mContentResolver);
        Settings.System.putIntForUser(mContentResolver, Settings.System.SCREEN_OFF_TIMEOUT,
                DEFAULT_SCREEN_OFF_TIMEOUT_MS, UserHandle.USER_CURRENT);

        final DisplayInfo info = new DisplayInfo();
@@ -511,6 +513,115 @@ public class WakefulnessSessionObserverTest {
                        DEFAULT_SCREEN_OFF_TIMEOUT_MS); // default Timeout Ms
    }

    @Test
    public void testScreenOffTimeout_normal_logSessionEventTriggered() {
        int powerGroupId = 1;
        int userActivity = PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY;
        triggerLogSessionEvent(powerGroupId, userActivity);
        verify(mWakefulnessSessionFrameworkStatsLogger)
                .logSessionEvent(
                        powerGroupId, // powerGroupId
                        OFF_REASON_TIMEOUT, // interactiveStateOffReason
                        0, // interactiveStateOnDurationMs
                        userActivity, // userActivity
                        0,  // lastUserActivityEventDurationMs
                        DEFAULT_SCREEN_OFF_TIMEOUT_MS - OVERRIDE_SCREEN_OFF_TIMEOUT_MS
                ); // reducedInteractiveStateOnDurationMs;
    }

    @Test
    public void testScreenOffTimeout_zero_noLogSessionEventTriggered() {
        // simulate adding an invalid screen_off_timeout value
        Settings.System.putIntForUser(mContentResolver, Settings.System.SCREEN_OFF_TIMEOUT,
                0, // invalid timeout value
                UserHandle.USER_CURRENT);
        mWakefulnessSessionObserver.updateSettingScreenOffTimeout(mContext);

        try {
            triggerLogSessionEvent();
            verify(mWakefulnessSessionFrameworkStatsLogger, never())
                    .logSessionEvent(anyInt(), anyInt(), anyLong(), anyInt(), anyLong(), anyInt());
        } finally {
            // rollback the original data
            Settings.System.putIntForUser(mContentResolver, Settings.System.SCREEN_OFF_TIMEOUT,
                    DEFAULT_SCREEN_OFF_TIMEOUT_MS, UserHandle.USER_CURRENT);
            mWakefulnessSessionObserver.updateSettingScreenOffTimeout(mContext);
        }
    }

    @Test
    public void testScreenOffTimeout_negative_noLogSessionEventTriggered() {
        // simulate adding an invalid screen_off_timeout value
        Settings.System.putIntForUser(mContentResolver, Settings.System.SCREEN_OFF_TIMEOUT,
                -1, // invalid timeout value
                UserHandle.USER_CURRENT);
        mWakefulnessSessionObserver.updateSettingScreenOffTimeout(mContext);

        try {
            triggerLogSessionEvent();
            verify(mWakefulnessSessionFrameworkStatsLogger, never())
                    .logSessionEvent(anyInt(), anyInt(), anyLong(), anyInt(), anyLong(), anyInt());
        } finally {
            // rollback the original data
            Settings.System.putIntForUser(mContentResolver, Settings.System.SCREEN_OFF_TIMEOUT,
                    DEFAULT_SCREEN_OFF_TIMEOUT_MS, UserHandle.USER_CURRENT);
            mWakefulnessSessionObserver.updateSettingScreenOffTimeout(mContext);
        }
    }

    @Test
    public void testScreenOffTimeout_max_logSessionEventTriggered() {
        // simulate adding the max screen_off_timeout value
        int defaultTimeoutMs = Integer.MAX_VALUE;
        Settings.System.putIntForUser(mContentResolver, Settings.System.SCREEN_OFF_TIMEOUT,
                defaultTimeoutMs,
                UserHandle.USER_CURRENT);
        mWakefulnessSessionObserver.updateSettingScreenOffTimeout(mContext);

        try {
            int powerGroupId = 1;
            int userActivity = PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY;
            triggerLogSessionEvent(powerGroupId, userActivity);
            verify(mWakefulnessSessionFrameworkStatsLogger)
                    .logSessionEvent(
                            powerGroupId, // powerGroupId
                            OFF_REASON_TIMEOUT, // interactiveStateOffReason
                            0, // interactiveStateOnDurationMs
                            userActivity, // userActivity
                            0,  // lastUserActivityEventDurationMs
                            defaultTimeoutMs - OVERRIDE_SCREEN_OFF_TIMEOUT_MS
                    ); // reducedInteractiveStateOnDurationMs;
        } finally {
            // rollback the original data
            Settings.System.putIntForUser(mContentResolver, Settings.System.SCREEN_OFF_TIMEOUT,
                    DEFAULT_SCREEN_OFF_TIMEOUT_MS, UserHandle.USER_CURRENT);
            mWakefulnessSessionObserver.updateSettingScreenOffTimeout(mContext);
        }
    }

    private void triggerLogSessionEvent() {
        triggerLogSessionEvent(1, PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY);
    }

    private void triggerLogSessionEvent(int powerGroupId, int userActivity) {
        mWakefulnessSessionObserver.onWakefulnessChangeStarted(
                powerGroupId,
                PowerManagerInternal.WAKEFULNESS_AWAKE,
                WAKE_REASON_POWER_BUTTON,
                mTestClock.now());
        mWakefulnessSessionObserver.onWakeLockAcquired(
                PowerManager.SCREEN_TIMEOUT_OVERRIDE_WAKE_LOCK);

        long userActivityTime = mTestClock.now();
        mWakefulnessSessionObserver.notifyUserActivity(
                userActivityTime, powerGroupId, userActivity);
        mWakefulnessSessionObserver.onWakefulnessChangeStarted(
                powerGroupId,
                PowerManagerInternal.WAKEFULNESS_DOZING,
                GO_TO_SLEEP_REASON_TIMEOUT,
                mTestClock.now());
    }

    private void advanceTime(long timeMs) {
        mTestClock.fastForward(timeMs);
    }