Loading services/core/java/com/android/server/power/Notifier.java +3 −1 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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; Loading Loading @@ -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); Loading services/core/java/com/android/server/power/WakefulnessSessionObserver.java +276 −9 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading @@ -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(); Loading @@ -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)); Loading @@ -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 * Loading Loading @@ -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; Loading @@ -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 Loading @@ -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; Loading @@ -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) { Loading @@ -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)) { Loading @@ -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, Loading @@ -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; Loading @@ -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; Loading @@ -393,6 +526,8 @@ public class WakefulnessSessionObserver { // state instantly mTimeoutOffTimestamp = eventTime; } checkAndLogDimIfQualified(POLICY_REASON_OFF_TIMEOUT, eventTime); } long interactiveStateOnDurationMs = Loading Loading @@ -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(); Loading @@ -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(); } } Loading Loading @@ -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; Loading Loading @@ -591,5 +850,13 @@ public class WakefulnessSessionObserver { Clock getClock() { return SystemClock::uptimeMillis; } Handler getHandler() { return BackgroundThread.getHandler(); } DisplayManagerInternal getDisplayManagerInternal() { return LocalServices.getService(DisplayManagerInternal.class); } } } Loading
services/core/java/com/android/server/power/Notifier.java +3 −1 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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; Loading Loading @@ -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); Loading
services/core/java/com/android/server/power/WakefulnessSessionObserver.java +276 −9 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading @@ -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(); Loading @@ -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)); Loading @@ -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 * Loading Loading @@ -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; Loading @@ -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 Loading @@ -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; Loading @@ -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) { Loading @@ -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)) { Loading @@ -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, Loading @@ -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; Loading @@ -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; Loading @@ -393,6 +526,8 @@ public class WakefulnessSessionObserver { // state instantly mTimeoutOffTimestamp = eventTime; } checkAndLogDimIfQualified(POLICY_REASON_OFF_TIMEOUT, eventTime); } long interactiveStateOnDurationMs = Loading Loading @@ -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(); Loading @@ -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(); } } Loading Loading @@ -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; Loading Loading @@ -591,5 +850,13 @@ public class WakefulnessSessionObserver { Clock getClock() { return SystemClock::uptimeMillis; } Handler getHandler() { return BackgroundThread.getHandler(); } DisplayManagerInternal getDisplayManagerInternal() { return LocalServices.getService(DisplayManagerInternal.class); } } }