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

Commit f8ad14ed authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Log screen dim event" into main

parents f154a120 6c18bcf9
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -206,7 +206,6 @@ public class Notifier {
        mPolicy = policy;
        mFaceDownDetector = faceDownDetector;
        mScreenUndimDetector = screenUndimDetector;
        mWakefulnessSessionObserver = new WakefulnessSessionObserver(mContext, null);
        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
        mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
        mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class);
@@ -214,6 +213,7 @@ public class Notifier {
        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
        mTrustManager = mContext.getSystemService(TrustManager.class);
        mVibrator = mContext.getSystemService(Vibrator.class);
        mWakefulnessSessionObserver = new WakefulnessSessionObserver(mContext, null);

        mHandler = new NotifierHandler(looper);
        mBackgroundExecutor = backgroundExecutor;
@@ -813,6 +813,8 @@ public class Notifier {
        if (DEBUG) {
            Slog.d(TAG, "onScreenPolicyUpdate: newPolicy=" + newPolicy);
        }
        mWakefulnessSessionObserver.onScreenPolicyUpdate(
                SystemClock.uptimeMillis(), displayGroupId, newPolicy);

        synchronized (mLock) {
            Message msg = mHandler.obtainMessage(MSG_SCREEN_POLICY);
+276 −9
Original line number Diff line number Diff line
@@ -16,8 +16,11 @@

package com.android.server.power;

import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM;
import static android.os.PowerManager.USER_ACTIVITY_EVENT_OTHER;
import static android.os.PowerManagerInternal.isInteractive;
import static android.view.Display.DEFAULT_DISPLAY;

import static com.android.server.power.PowerManagerService.DEFAULT_SCREEN_OFF_TIMEOUT;
import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_NON_INTERACTIVE;
@@ -34,6 +37,9 @@ import android.app.ActivityManager;
import android.app.SynchronousUserSwitchObserver;
import android.content.Context;
import android.database.ContentObserver;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerManagerInternal;
@@ -44,9 +50,13 @@ import android.provider.Settings;
import android.util.IndentingPrintWriter;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayAddress;
import android.view.DisplayInfo;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;

import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -117,9 +127,42 @@ public class WakefulnessSessionObserver {
    @Retention(RetentionPolicy.SOURCE)
    private @interface OverrideOutcome {}

    private static final int DEFAULT_USER_ACTIVITY = USER_ACTIVITY_EVENT_OTHER;
    private static final long TIMEOUT_USER_INITIATED_REVERT_THRESHOLD_MILLIS = 5000L;
    private static final int POLICY_REASON_UNKNOWN = FrameworkStatsLog
            .SCREEN_DIM_REPORTED__POLICY_REASON__UNKNOWN;
    @VisibleForTesting
    protected 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
            .SCREEN_DIM_REPORTED__POLICY_REASON__OFF_POWER_BUTTON;
    @VisibleForTesting
    protected 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
            .SCREEN_DIM_REPORTED__POLICY_REASON__BRIGHT_INITIATED_REVERT;

    /**
     * Policy Reason
     * {@link android.os.statsd.power.ScreenDimReported.PolicyReason}.
     */
    @IntDef(prefix = {"POLICY_REASON_"}, value = {
            POLICY_REASON_UNKNOWN,
            POLICY_REASON_OFF_TIMEOUT,
            POLICY_REASON_OFF_POWER_BUTTON,
            POLICY_REASON_BRIGHT_UNDIM,
            POLICY_REASON_BRIGHT_INITIATED_REVERT
    })
    @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;

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

    private Context mContext;
    private int mScreenOffTimeoutMs;
@@ -130,17 +173,24 @@ public class WakefulnessSessionObserver {
    protected WakefulnessSessionFrameworkStatsLogger mWakefulnessSessionFrameworkStatsLogger;
    private final Clock mClock;
    private final Object mLock = new Object();
    private final Handler mHandler;

    public WakefulnessSessionObserver(Context context, Injector injector) {
    private DisplayManagerInternal mDisplayManagerInternal;
    private int mPhysicalDisplayPortIdForDefaultDisplay;

    public WakefulnessSessionObserver(
            Context context, Injector injector) {
        if (injector == null) {
            injector = new Injector();
        }

        mContext = context;
        mDisplayManagerInternal = injector.getDisplayManagerInternal();
        mWakefulnessSessionFrameworkStatsLogger = injector
                .getWakefulnessSessionFrameworkStatsLogger();
        mClock = injector.getClock();
        updateSettingScreenOffTimeout(context);
        mHandler = injector.getHandler();
        updateSettingScreenOffTimeout(mContext);

        try {
            final UserSwitchObserver observer = new UserSwitchObserver();
@@ -164,6 +214,31 @@ public class WakefulnessSessionObserver {
                        },
                        UserHandle.USER_ALL);

        mPhysicalDisplayPortIdForDefaultDisplay = getPhysicalDisplayPortId(DEFAULT_DISPLAY);
        DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
        if (displayManager != null) {
            displayManager.registerDisplayListener(
                    new DisplayManager.DisplayListener() {
                        @Override
                        public void onDisplayChanged(int displayId) {
                            if (displayId == DEFAULT_DISPLAY) {
                                mPhysicalDisplayPortIdForDefaultDisplay = getPhysicalDisplayPortId(
                                        DEFAULT_DISPLAY);
                            }
                        }

                        @Override
                        public void onDisplayAdded(int i) {
                        }

                        @Override
                        public void onDisplayRemoved(int i) {
                        }
                    },
                    mHandler,
                    DisplayManager.EVENT_FLAG_DISPLAY_CHANGED);
        }

        mPowerGroups.append(
                Display.DEFAULT_DISPLAY_GROUP,
                new WakefulnessSessionPowerGroup(Display.DEFAULT_DISPLAY_GROUP));
@@ -185,6 +260,20 @@ public class WakefulnessSessionObserver {
        mPowerGroups.get(powerGroupId).notifyUserActivity(eventTime, event);
    }

    /**
     * Track the screen policy
     *
     * @param eventTime policy changing time, in uptime millis.
     * @param powerGroupId Power Group Id for this screen policy
     * @param newPolicy Screen Policy defined in {@link DisplayPowerRequest}
     */
    public void onScreenPolicyUpdate(long eventTime, int powerGroupId, int newPolicy) {
        if (!mPowerGroups.contains(powerGroupId)) {
            mPowerGroups.append(powerGroupId, new WakefulnessSessionPowerGroup(powerGroupId));
        }
        mPowerGroups.get(powerGroupId).onScreenPolicyUpdate(eventTime, newPolicy);
    }

    /**
     * Track the system wakefulness
     *
@@ -267,6 +356,14 @@ public class WakefulnessSessionObserver {
        }
    }

    private int getPhysicalDisplayPortId(int displayId) {
        if (mDisplayManagerInternal == null) {
            return -1;
        }
        DisplayInfo display = mDisplayManagerInternal.getDisplayInfo(displayId);
        return ((DisplayAddress.Physical) display.address).getPort();
    }

    private int getScreenOffTimeout() {
        synchronized (mLock) {
            return mScreenOffTimeoutMs;
@@ -277,10 +374,9 @@ public class WakefulnessSessionObserver {
    @VisibleForTesting
    protected class WakefulnessSessionPowerGroup {
        private static final long TIMEOUT_OFF_RESET_TIMESTAMP = -1;

        private int mPowerGroupId;
        private int mCurrentWakefulness;
        private boolean mIsInteractive = false;
        @VisibleForTesting protected boolean mIsInteractive = false;
        // state on start timestamp: will be used in state off to calculate the duration of state on
        private long mInteractiveStateOnStartTimestamp;
        @VisibleForTesting
@@ -295,6 +391,17 @@ public class WakefulnessSessionObserver {
        private int mTimeoutOverrideWakeLockCounter = 0;
        // The timestamp when Override Timeout is set to false
        private @ScreenTimeoutOverridePolicy.ReleaseReason int mTimeoutOverrideReleaseReason;
        // The timestamp when current screen policy is set
        private long mCurrentScreenPolicyTimestamp;
        // current screen policy
        private int mCurrentScreenPolicy;
        // The screen policy before the current one
        private int mPrevScreenPolicy;
        // The previous screen policy duration
        private int mPrevScreenPolicyDurationMs;
        // The past dim duration
        @VisibleForTesting protected int mPastDimDurationMs;
        private long mInteractiveOffTimestamp;
        // The timestamp when state off by timeout occurs
        // will set TIMEOUT_OFF_RESET_TIMESTAMP if state on or state off by power button
        private long mTimeoutOffTimestamp;
@@ -307,6 +414,10 @@ public class WakefulnessSessionObserver {
            mPrevUserActivityEvent = DEFAULT_USER_ACTIVITY;
            mPrevUserActivityTimestamp = -1;
            mPowerGroupId = powerGroupId;
            mCurrentScreenPolicy = mPrevScreenPolicy = POLICY_BRIGHT;
            mCurrentScreenPolicyTimestamp = 0;
            mPrevScreenPolicyDurationMs = 0;
            mPastDimDurationMs = 0;
        }

        public void notifyUserActivity(long eventTime, @PowerManager.UserActivityEvent int event) {
@@ -320,6 +431,21 @@ public class WakefulnessSessionObserver {
            mCurrentUserActivityTimestamp = eventTime;
        }

        public void onScreenPolicyUpdate(long eventTime, int newPolicy) {
            if (newPolicy == mCurrentScreenPolicy) {
                return;
            }

            if (newPolicy == POLICY_BRIGHT) {
                checkAndLogDimIfQualified(POLICY_REASON_BRIGHT_UNDIM, eventTime);
            }

            mPrevScreenPolicy = mCurrentScreenPolicy;
            mCurrentScreenPolicy = newPolicy;
            mPrevScreenPolicyDurationMs = (int) (eventTime - mCurrentScreenPolicyTimestamp);
            mCurrentScreenPolicyTimestamp = eventTime;
        }

        public void onWakefulnessChangeStarted(int wakefulness, int changeReason, long eventTime) {
            mCurrentWakefulness = wakefulness;
            if (mIsInteractive == isInteractive(wakefulness)) {
@@ -331,10 +457,10 @@ public class WakefulnessSessionObserver {
                mInteractiveStateOnStartTimestamp = eventTime;

                // Log the outcome of screen timeout override (USER INITIATED REVERT),
                // when user initiates to revert the screen off state in a short period.
                // when user initiates to revert the off state in a short period.
                if (mTimeoutOffTimestamp != TIMEOUT_OFF_RESET_TIMESTAMP) {
                    long offToOnDurationMs = eventTime - mTimeoutOffTimestamp;
                    if (offToOnDurationMs < TIMEOUT_USER_INITIATED_REVERT_THRESHOLD_MILLIS) {
                    long timeoutOffToOnDurationMs = eventTime - mTimeoutOffTimestamp;
                    if (timeoutOffToOnDurationMs < USER_INITIATED_REVERT_THRESHOLD_MILLIS) {
                        mWakefulnessSessionFrameworkStatsLogger.logTimeoutOverrideEvent(
                                mPowerGroupId,
                                OVERRIDE_OUTCOME_TIMEOUT_USER_INITIATED_REVERT,
@@ -344,11 +470,15 @@ public class WakefulnessSessionObserver {
                    }
                    mTimeoutOffTimestamp = TIMEOUT_OFF_RESET_TIMESTAMP;
                }

                checkAndLogDimIfQualified(POLICY_REASON_BRIGHT_INITIATED_REVERT, eventTime);

            } else {
                int lastUserActivity = mCurrentUserActivityEvent;
                long lastUserActivityDurationMs = eventTime - mCurrentUserActivityTimestamp;
                @OffReason int interactiveStateOffReason = OFF_REASON_UNKNOWN;
                int reducedInteractiveStateOnDurationMs = 0;
                mInteractiveOffTimestamp = eventTime;

                if (changeReason == PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON) {
                    interactiveStateOffReason = OFF_REASON_POWER_BUTTON;
@@ -369,6 +499,9 @@ public class WakefulnessSessionObserver {
                        mSendOverrideTimeoutLogTimestamp = eventTime;
                        mTimeoutOverrideReleaseReason = RELEASE_REASON_UNKNOWN; // reset the reason
                    }

                    checkAndLogDimIfQualified(POLICY_REASON_OFF_POWER_BUTTON, eventTime);

                } else if (changeReason == PowerManager.GO_TO_SLEEP_REASON_TIMEOUT) {
                    // Interactive Off reason is timeout
                    interactiveStateOffReason = OFF_REASON_TIMEOUT;
@@ -393,6 +526,8 @@ public class WakefulnessSessionObserver {
                        // state instantly
                        mTimeoutOffTimestamp = eventTime;
                    }

                    checkAndLogDimIfQualified(POLICY_REASON_OFF_TIMEOUT, eventTime);
                }

                long interactiveStateOnDurationMs =
@@ -462,6 +597,106 @@ public class WakefulnessSessionObserver {
            }
        }

        private void checkAndLogDimIfQualified(
                @PolicyReason int reasonToBeChecked, long eventTime) {
            // Only log dim event when DEFAULT_DISPLAY
            if (mPowerGroupId != DEFAULT_DISPLAY) {
                return;
            }

            int dimDurationMs = 0;
            int lastUserActivity = mCurrentUserActivityEvent;
            int lastUserActivityDurationMs = (int) (eventTime - mCurrentUserActivityTimestamp);
            switch (reasonToBeChecked) {
                case POLICY_REASON_OFF_TIMEOUT: {
                    // The policy ordering:
                    // (1) --DIM--OFF/DOZE->| or (2) --DIM->| because OFF/DOZE hasn't been updated.
                    dimDurationMs = (int) (eventTime - mCurrentScreenPolicyTimestamp); //(1)--DIM->|
                    if (mPrevScreenPolicy == POLICY_DIM) {  // for (2) --DIM--OFF/DOZE->|
                        dimDurationMs = mPrevScreenPolicyDurationMs;
                    }
                    mWakefulnessSessionFrameworkStatsLogger.logDimEvent(
                            mPhysicalDisplayPortIdForDefaultDisplay,
                            reasonToBeChecked,
                            lastUserActivity,
                            lastUserActivityDurationMs,
                            dimDurationMs,
                            mScreenOffTimeoutMs);
                    mPastDimDurationMs = dimDurationMs;
                    return;
                }
                case POLICY_REASON_OFF_POWER_BUTTON: {
                    // Power Off will be triggered by USER_ACTIVITY_EVENT_BUTTON
                    // The metric wants to record the previous activity before EVENT_BUTTON
                    lastUserActivity = mPrevUserActivityEvent;
                    lastUserActivityDurationMs = (int) (eventTime - mPrevUserActivityTimestamp);
                    // the policy ordering:
                    // (1) ---BRIGHT->| or (2) ---DIM->| because OFF/DOZE hasn't been updated
                    dimDurationMs = 0; // for (1) ---BRIGHT->| which doesn't have dim (no need log)
                    if (mCurrentScreenPolicy == POLICY_DIM) { // for (2) ---DIM->|
                        dimDurationMs = (int) (eventTime - mCurrentScreenPolicyTimestamp);
                        mWakefulnessSessionFrameworkStatsLogger.logDimEvent(
                                mPhysicalDisplayPortIdForDefaultDisplay,
                                reasonToBeChecked,
                                lastUserActivity,
                                lastUserActivityDurationMs,
                                dimDurationMs,
                                mScreenOffTimeoutMs);
                        mHandler.removeCallbacksAndMessages(HANDLER_TOKEN);
                    }

                    mPastDimDurationMs = dimDurationMs;
                    return;
                }
                case POLICY_REASON_BRIGHT_UNDIM: {
                    // Has checked the latest screen policy is POLICY_BRIGHT in onScreenPolicyUpdate
                    if (mCurrentScreenPolicy == POLICY_DIM) { // policy ordering: --DIM--BRIGHT->|
                        int savedDimDurationMs = (int) (eventTime - mCurrentScreenPolicyTimestamp);
                        int savedLastUserActivity = lastUserActivity;
                        int savedLastUserActivityDurationMs = lastUserActivityDurationMs;

                        // For the undim case --DIM--BRIGHT->|, it needs wait 500 ms to
                        // differentiate between "power button off" case, which is
                        // --DIM--BRIGHT(<500ms)--OFF/DOZE->|
                        // [Method] Wait 500 ms to see whether triggers power button off or not.
                        // [Reason] We got --DIM--BRIGHT->|. However, if BRIGHT is so short (<500ms)
                        //          and follows OFF/DOZE, it represents power button off, not undim.
                        //          It is normal to have a short BRIGHT for power button off because
                        //          the system need to play an animation before off.
                        mHandler.postDelayed(() -> {
                            mWakefulnessSessionFrameworkStatsLogger.logDimEvent(
                                    mPhysicalDisplayPortIdForDefaultDisplay,
                                    reasonToBeChecked,
                                    savedLastUserActivity,
                                    savedLastUserActivityDurationMs,
                                    savedDimDurationMs,
                                    mScreenOffTimeoutMs);
                            mPastDimDurationMs = savedDimDurationMs;
                        }, HANDLER_TOKEN, SCREEN_POLICY_DIM_POWER_OFF_BRIGHT_THRESHOLD_MILLIS);
                    }
                    return;
                }
                case POLICY_REASON_BRIGHT_INITIATED_REVERT: {
                    // the dimDuration in BRIGHT_INITIATE_REVERT is for the dim duration before
                    // screen interactive off (mPastDimDurationMs)
                    long offToOnDurationMs = eventTime - mInteractiveOffTimestamp;
                    if (mPastDimDurationMs > 0
                            && offToOnDurationMs < USER_INITIATED_REVERT_THRESHOLD_MILLIS) {
                        mWakefulnessSessionFrameworkStatsLogger.logDimEvent(
                                mPhysicalDisplayPortIdForDefaultDisplay,
                                reasonToBeChecked,
                                lastUserActivity,
                                lastUserActivityDurationMs,
                                mPastDimDurationMs,
                                mScreenOffTimeoutMs);
                    }
                    return;
                }
                default:
                    return;
            }
        }

        void dump(IndentingPrintWriter writer) {
            final long now = mClock.uptimeMillis();

@@ -475,6 +710,12 @@ public class WakefulnessSessionObserver {
            final long prevUserActivityDurationMs = now - mPrevUserActivityTimestamp;
            writer.println("previous user activity duration: " + prevUserActivityDurationMs);
            writer.println("is in override timeout: " + isInOverrideTimeout());
            writer.println("mIsInteractive: " + mIsInteractive);
            writer.println("current screen policy: " + mCurrentScreenPolicy);
            final long currentScreenPolicyDurationMs = now - mCurrentScreenPolicyTimestamp;
            writer.println("current screen policy duration: " + currentScreenPolicyDurationMs);
            writer.println("previous screen policy: " + mPrevScreenPolicy);
            writer.println("past screen policy duration: " + mPrevScreenPolicyDurationMs);
            writer.decreaseIndent();
        }
    }
@@ -512,6 +753,24 @@ public class WakefulnessSessionObserver {
                    (long) defaultTimeoutMs);
        }

        public void logDimEvent(
                int physicalDisplayPortId,
                @PolicyReason int policyReason,
                @PowerManager.UserActivityEvent int userActivityEvent,
                int lastUserActivityEventDurationMs,
                int dimDurationMs,
                int defaultTimeoutMs) {
            int logUserActivityEvent = convertToLogUserActivityEvent(userActivityEvent);
            FrameworkStatsLog.write(
                    FrameworkStatsLog.SCREEN_DIM_REPORTED,
                    physicalDisplayPortId,
                    policyReason,
                    logUserActivityEvent,
                    lastUserActivityEventDurationMs,
                    dimDurationMs,
                    defaultTimeoutMs);
        }

        private static final int USER_ACTIVITY_OTHER = FrameworkStatsLog
                .SCREEN_INTERACTIVE_SESSION_REPORTED__LAST_USER_ACTIVITY_EVENT__OTHER;

@@ -591,5 +850,13 @@ public class WakefulnessSessionObserver {
        Clock getClock() {
            return SystemClock::uptimeMillis;
        }

        Handler getHandler() {
            return BackgroundThread.getHandler();
        }

        DisplayManagerInternal getDisplayManagerInternal() {
            return LocalServices.getService(DisplayManagerInternal.class);
        }
    }
}