• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.power;
18 
19 import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
20 import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM;
21 import static android.os.PowerManager.USER_ACTIVITY_EVENT_OTHER;
22 import static android.os.PowerManagerInternal.isInteractive;
23 import static android.view.Display.DEFAULT_DISPLAY;
24 
25 import static com.android.server.power.PowerManagerService.DEFAULT_SCREEN_OFF_TIMEOUT;
26 import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_NON_INTERACTIVE;
27 import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_SCREEN_LOCK;
28 import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_UNKNOWN;
29 import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_USER_ACTIVITY_ACCESSIBILITY;
30 import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_USER_ACTIVITY_ATTENTION;
31 import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_USER_ACTIVITY_BUTTON;
32 import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_USER_ACTIVITY_OTHER;
33 import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_USER_ACTIVITY_TOUCH;
34 import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_WAKE_LOCK_DEATH;
35 
36 import android.annotation.IntDef;
37 import android.app.ActivityManager;
38 import android.app.SynchronousUserSwitchObserver;
39 import android.content.Context;
40 import android.database.ContentObserver;
41 import android.hardware.display.DisplayManager;
42 import android.hardware.display.DisplayManagerInternal;
43 import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
44 import android.os.Handler;
45 import android.os.PowerManager;
46 import android.os.PowerManagerInternal;
47 import android.os.RemoteException;
48 import android.os.SystemClock;
49 import android.os.UserHandle;
50 import android.provider.Settings;
51 import android.util.IndentingPrintWriter;
52 import android.util.Slog;
53 import android.util.SparseArray;
54 import android.view.Display;
55 import android.view.DisplayAddress;
56 import android.view.DisplayInfo;
57 
58 import com.android.internal.annotations.VisibleForTesting;
59 import com.android.internal.os.BackgroundThread;
60 import com.android.internal.util.FrameworkStatsLog;
61 import com.android.server.LocalServices;
62 
63 import java.io.PrintWriter;
64 import java.lang.annotation.Retention;
65 import java.lang.annotation.RetentionPolicy;
66 
67 /**
68  * Observe the wakefulness session of the device, tracking the reason and the
69  * last user activity when the interactive state is off.
70  */
71 public class WakefulnessSessionObserver {
72     private static final String TAG = "WakefulnessSessionObserver";
73 
74     static final int OFF_REASON_UNKNOWN = FrameworkStatsLog
75             .SCREEN_INTERACTIVE_SESSION_REPORTED__INTERACTIVE_STATE_OFF_REASON__UNKNOWN;
76     static final int OFF_REASON_TIMEOUT = FrameworkStatsLog
77             .SCREEN_INTERACTIVE_SESSION_REPORTED__INTERACTIVE_STATE_OFF_REASON__TIMEOUT;
78     static final int OFF_REASON_POWER_BUTTON = FrameworkStatsLog
79             .SCREEN_INTERACTIVE_SESSION_REPORTED__INTERACTIVE_STATE_OFF_REASON__POWER_BUTTON;
80 
81     /**
82      * Interactive off reason
83      * {@link android.os.statsd.power.ScreenInteractiveSessionReported.InteractiveStateOffReason}.
84      */
85     @IntDef(prefix = {"OFF_REASON_"}, value = {
86             OFF_REASON_UNKNOWN,
87             OFF_REASON_TIMEOUT,
88             OFF_REASON_POWER_BUTTON
89     })
90     @Retention(RetentionPolicy.SOURCE)
91     private @interface OffReason {}
92 
93     static final int OVERRIDE_OUTCOME_UNKNOWN = FrameworkStatsLog
94             .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__UNKNOWN;
95     static final int OVERRIDE_OUTCOME_TIMEOUT_SUCCESS = FrameworkStatsLog
96             .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__TIMEOUT_SUCCESS;
97     static final int OVERRIDE_OUTCOME_TIMEOUT_USER_INITIATED_REVERT = FrameworkStatsLog
98             .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__TIMEOUT_USER_INITIATED_REVERT;
99     static final int OVERRIDE_OUTCOME_CANCEL_CLIENT_API_CALL = FrameworkStatsLog
100             .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__CANCEL_CLIENT_API_CALL;
101     static final int OVERRIDE_OUTCOME_CANCEL_USER_INTERACTION = FrameworkStatsLog
102             .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__CANCEL_USER_INTERACTION;
103     static final int OVERRIDE_OUTCOME_CANCEL_POWER_BUTTON = FrameworkStatsLog
104             .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__CANCEL_POWER_BUTTON;
105     static final int OVERRIDE_OUTCOME_CANCEL_CLIENT_DISCONNECT = FrameworkStatsLog
106             .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__CANCEL_CLIENT_DISCONNECTED;
107     static final int OVERRIDE_OUTCOME_CANCEL_OTHER = FrameworkStatsLog
108             .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__CANCEL_OTHER;
109 
110     /**
111      * Override Outcome
112      * {@link android.os.statsd.power.ScreenTimeoutOverrideReported.OverrideOutcome}.
113      */
114     @IntDef(prefix = {"OVERRIDE_OUTCOME_"}, value = {
115             OVERRIDE_OUTCOME_UNKNOWN,
116             OVERRIDE_OUTCOME_TIMEOUT_SUCCESS,
117             OVERRIDE_OUTCOME_TIMEOUT_USER_INITIATED_REVERT,
118             OVERRIDE_OUTCOME_CANCEL_CLIENT_API_CALL,
119             OVERRIDE_OUTCOME_CANCEL_USER_INTERACTION,
120             OVERRIDE_OUTCOME_CANCEL_POWER_BUTTON,
121             OVERRIDE_OUTCOME_CANCEL_CLIENT_DISCONNECT,
122             OVERRIDE_OUTCOME_CANCEL_OTHER
123     })
124     @Retention(RetentionPolicy.SOURCE)
125     private @interface OverrideOutcome {}
126 
127     static final int POLICY_REASON_UNKNOWN = FrameworkStatsLog
128             .SCREEN_DIM_REPORTED__POLICY_REASON__UNKNOWN;
129     static final int POLICY_REASON_OFF_TIMEOUT = FrameworkStatsLog
130             .SCREEN_DIM_REPORTED__POLICY_REASON__OFF_TIMEOUT;
131     static final int POLICY_REASON_OFF_POWER_BUTTON = FrameworkStatsLog
132             .SCREEN_DIM_REPORTED__POLICY_REASON__OFF_POWER_BUTTON;
133     static final int POLICY_REASON_BRIGHT_UNDIM = FrameworkStatsLog
134             .SCREEN_DIM_REPORTED__POLICY_REASON__BRIGHT_UNDIM;
135     static final int POLICY_REASON_BRIGHT_INITIATED_REVERT = FrameworkStatsLog
136             .SCREEN_DIM_REPORTED__POLICY_REASON__BRIGHT_INITIATED_REVERT;
137 
138     /**
139      * Policy Reason
140      * {@link android.os.statsd.power.ScreenDimReported.PolicyReason}.
141      */
142     @IntDef(prefix = {"POLICY_REASON_"}, value = {
143             POLICY_REASON_UNKNOWN,
144             POLICY_REASON_OFF_TIMEOUT,
145             POLICY_REASON_OFF_POWER_BUTTON,
146             POLICY_REASON_BRIGHT_UNDIM,
147             POLICY_REASON_BRIGHT_INITIATED_REVERT
148     })
149     @Retention(RetentionPolicy.SOURCE)
150     private @interface PolicyReason {}
151 
152     static final int DEFAULT_USER_ACTIVITY = USER_ACTIVITY_EVENT_OTHER;
153     static final long USER_INITIATED_REVERT_THRESHOLD_MILLIS = 5000L;
154     static final long SEND_OVERRIDE_TIMEOUT_LOG_THRESHOLD_MILLIS = 1000L;
155     static final long SCREEN_POLICY_DIM_POWER_OFF_BRIGHT_THRESHOLD_MILLIS = 500L;
156 
157     static final Object HANDLER_TOKEN = new Object();
158 
159     private Context mContext;
160     private int mScreenOffTimeoutMs;
161     private int mOverrideTimeoutMs = 0;
162     final SparseArray<WakefulnessSessionPowerGroup> mPowerGroups = new SparseArray<>();
163     WakefulnessSessionFrameworkStatsLogger mWakefulnessSessionFrameworkStatsLogger;
164     private final Clock mClock;
165     private final Object mLock = new Object();
166     private final Handler mHandler;
167 
168     private DisplayManagerInternal mDisplayManagerInternal;
169     private int mPhysicalDisplayPortIdForDefaultDisplay;
170 
WakefulnessSessionObserver( Context context, Injector injector)171     public WakefulnessSessionObserver(
172             Context context, Injector injector) {
173         if (injector == null) {
174             injector = new Injector();
175         }
176 
177         mContext = context;
178         mDisplayManagerInternal = injector.getDisplayManagerInternal();
179         mWakefulnessSessionFrameworkStatsLogger = injector
180                 .getWakefulnessSessionFrameworkStatsLogger();
181         mClock = injector.getClock();
182         mHandler = injector.getHandler();
183         updateSettingScreenOffTimeout(mContext);
184 
185         try {
186             final UserSwitchObserver observer = new UserSwitchObserver();
187             ActivityManager.getService().registerUserSwitchObserver(observer, TAG);
188         } catch (RemoteException e) {
189             // Shouldn't happen since in-process.
190         }
191 
192         mOverrideTimeoutMs = mContext.getResources().getInteger(
193                 com.android.internal.R.integer.config_screenTimeoutOverride);
194 
195         mContext.getContentResolver()
196                 .registerContentObserver(
197                         Settings.System.getUriFor(Settings.System.SCREEN_OFF_TIMEOUT),
198                         false,
199                         new ContentObserver(new Handler(mContext.getMainLooper())) {
200                             @Override
201                             public void onChange(boolean selfChange) {
202                                 updateSettingScreenOffTimeout(mContext);
203                             }
204                         },
205                         UserHandle.USER_ALL);
206 
207         mPhysicalDisplayPortIdForDefaultDisplay = getPhysicalDisplayPortId(DEFAULT_DISPLAY);
208         registerDisplayListener();
209         mPowerGroups.append(
210                 Display.DEFAULT_DISPLAY_GROUP,
211                 new WakefulnessSessionPowerGroup(Display.DEFAULT_DISPLAY_GROUP));
212     }
213 
registerDisplayListener()214     private void registerDisplayListener() {
215         DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
216         if (displayManager != null) {
217             displayManager.registerDisplayListener(
218                     new DisplayManager.DisplayListener() {
219                         @Override
220                         public void onDisplayChanged(int displayId) {
221                             if (displayId == DEFAULT_DISPLAY) {
222                                 mPhysicalDisplayPortIdForDefaultDisplay = getPhysicalDisplayPortId(
223                                         DEFAULT_DISPLAY);
224                             }
225                         }
226 
227                         @Override
228                         public void onDisplayAdded(int i) {
229                         }
230 
231                         @Override
232                         public void onDisplayRemoved(int i) {
233                         }
234                     },
235                     mHandler,
236                     DisplayManager.EVENT_TYPE_DISPLAY_CHANGED);
237         }
238     }
239 
240     /**
241      * Track the user activity event.
242      *
243      * @param eventTime Activity time, in uptime millis.
244      * @param powerGroupId Power Group Id for this user activity
245      * @param event Activity type as defined in {@link PowerManager}. {@link
246      *     android.hardware.display.DisplayManagerInternal.DisplayPowerRequest}
247      */
notifyUserActivity( long eventTime, int powerGroupId, @PowerManager.UserActivityEvent int event)248     public void notifyUserActivity(
249             long eventTime, int powerGroupId, @PowerManager.UserActivityEvent int event) {
250         if (!mPowerGroups.contains(powerGroupId)) {
251             mPowerGroups.append(powerGroupId, new WakefulnessSessionPowerGroup(powerGroupId));
252         }
253         mPowerGroups.get(powerGroupId).notifyUserActivity(eventTime, event);
254     }
255 
256     /**
257      * Track the screen policy
258      *
259      * @param eventTime policy changing time, in uptime millis.
260      * @param powerGroupId Power Group Id for this screen policy
261      * @param newPolicy Screen Policy defined in {@link DisplayPowerRequest}
262      */
onScreenPolicyUpdate(long eventTime, int powerGroupId, int newPolicy)263     public void onScreenPolicyUpdate(long eventTime, int powerGroupId, int newPolicy) {
264         if (!mPowerGroups.contains(powerGroupId)) {
265             mPowerGroups.append(powerGroupId, new WakefulnessSessionPowerGroup(powerGroupId));
266         }
267         mPowerGroups.get(powerGroupId).onScreenPolicyUpdate(eventTime, newPolicy);
268     }
269 
270     /**
271      * Track the system wakefulness
272      *
273      * @param powerGroupId Power Group Id for this wakefulness changes
274      * @param wakefulness Wakefulness as defined in {@link PowerManagerInternal}
275      * @param changeReason Reason of the go to sleep in
276      * {@link PowerManager.GoToSleepReason} or {@link PowerManager.WakeReason}
277      * @param eventTime timestamp of the wakefulness changes
278      */
onWakefulnessChangeStarted(int powerGroupId, int wakefulness, int changeReason, long eventTime)279     public void onWakefulnessChangeStarted(int powerGroupId, int wakefulness, int changeReason,
280             long eventTime) {
281         if (!mPowerGroups.contains(powerGroupId)) {
282             mPowerGroups.append(powerGroupId, new WakefulnessSessionPowerGroup(powerGroupId));
283         }
284         mPowerGroups.get(powerGroupId).onWakefulnessChangeStarted(wakefulness, changeReason,
285                 eventTime);
286     }
287 
288     /**
289      * Track the acquired wakelocks
290      *
291      * @param flags wakelocks to be acquired {@link PowerManager}
292      */
onWakeLockAcquired(int flags)293     public void onWakeLockAcquired(int flags) {
294         int maskedFlag = flags & PowerManager.WAKE_LOCK_LEVEL_MASK;
295         if (maskedFlag == PowerManager.SCREEN_TIMEOUT_OVERRIDE_WAKE_LOCK) {
296             for (int idx = 0; idx < mPowerGroups.size(); idx++) {
297                 mPowerGroups.valueAt(idx).acquireTimeoutOverrideWakeLock();
298             }
299         }
300     }
301 
302     /**
303      * Track the released wakelocks
304      *
305      * @param flags wakelocks to be released {@link PowerManager}
306      * @param releaseReason the reason to release wakelock
307      * {@link ScreenTimeoutOverridePolicy.ReleaseReason}
308      */
onWakeLockReleased(int flags, int releaseReason)309     public void onWakeLockReleased(int flags, int releaseReason) {
310         int maskedFlag = flags & PowerManager.WAKE_LOCK_LEVEL_MASK;
311         if (maskedFlag == PowerManager.SCREEN_TIMEOUT_OVERRIDE_WAKE_LOCK) {
312             for (int idx = 0; idx < mPowerGroups.size(); idx++) {
313                 mPowerGroups.valueAt(idx).releaseTimeoutOverrideWakeLock(releaseReason);
314             }
315         }
316     }
317 
318     /**
319      * Remove the inactive power group
320      *
321      * @param powerGroupId Power Group Id that should be removed
322      */
removePowerGroup(int powerGroupId)323     public void removePowerGroup(int powerGroupId) {
324         if (mPowerGroups.contains((powerGroupId))) {
325             mPowerGroups.delete(powerGroupId);
326         }
327     }
328 
dump(PrintWriter writer)329     void dump(PrintWriter writer) {
330         writer.println();
331         writer.println("Wakefulness Session Observer:");
332         writer.println("default timeout: " + mScreenOffTimeoutMs);
333         writer.println("override timeout: " + mOverrideTimeoutMs);
334         IndentingPrintWriter indentingPrintWriter = new IndentingPrintWriter(writer);
335         indentingPrintWriter.increaseIndent();
336         for (int idx = 0; idx < mPowerGroups.size(); idx++) {
337             mPowerGroups.valueAt(idx).dump(indentingPrintWriter);
338         }
339         writer.println();
340     }
341 
342     @VisibleForTesting
updateSettingScreenOffTimeout(Context context)343     void updateSettingScreenOffTimeout(Context context) {
344         synchronized (mLock) {
345             mScreenOffTimeoutMs = Settings.System.getIntForUser(
346                     context.getContentResolver(),
347                     Settings.System.SCREEN_OFF_TIMEOUT,
348                     DEFAULT_SCREEN_OFF_TIMEOUT,
349                     UserHandle.USER_CURRENT);
350         }
351     }
352 
getPhysicalDisplayPortId(int displayId)353     private int getPhysicalDisplayPortId(int displayId) {
354         if (mDisplayManagerInternal == null) {
355             return -1;
356         }
357         DisplayInfo display = mDisplayManagerInternal.getDisplayInfo(displayId);
358         return ((DisplayAddress.Physical) display.address).getPort();
359     }
360 
getScreenOffTimeout()361     private int getScreenOffTimeout() {
362         synchronized (mLock) {
363             return mScreenOffTimeoutMs;
364         }
365     }
366 
367     /** Screen Session by each power group */
368     @VisibleForTesting
369     protected class WakefulnessSessionPowerGroup {
370         private static final long TIMEOUT_OFF_RESET_TIMESTAMP = -1;
371         private int mPowerGroupId;
372         private int mCurrentWakefulness;
373         @VisibleForTesting protected boolean mIsInteractive = false;
374         // state on start timestamp: will be used in state off to calculate the duration of state on
375         private long mInteractiveStateOnStartTimestamp;
376         @VisibleForTesting
377         protected long mCurrentUserActivityTimestamp;
378         @VisibleForTesting
379         protected @PowerManager.UserActivityEvent int mCurrentUserActivityEvent;
380         @VisibleForTesting
381         protected long mPrevUserActivityTimestamp;
382         @VisibleForTesting
383         protected @PowerManager.UserActivityEvent int mPrevUserActivityEvent;
384         // to track the Override Timeout is set (that is, on SCREEN_TIMEOUT_OVERRIDE_WAKE_LOCK)
385         private int mTimeoutOverrideWakeLockCounter = 0;
386         // The timestamp when Override Timeout is set to false
387         private @ScreenTimeoutOverridePolicy.ReleaseReason int mTimeoutOverrideReleaseReason;
388         // The timestamp when current screen policy is set
389         private long mCurrentScreenPolicyTimestamp;
390         // current screen policy
391         private int mCurrentScreenPolicy;
392         // The screen policy before the current one
393         private int mPrevScreenPolicy;
394         // The previous screen policy duration
395         private int mPrevScreenPolicyDurationMs;
396         // The past dim duration
397         @VisibleForTesting protected int mPastDimDurationMs;
398         private long mInteractiveOffTimestamp;
399         // The timestamp when state off by timeout occurs
400         // will set TIMEOUT_OFF_RESET_TIMESTAMP if state on or state off by power button
401         private long mTimeoutOffTimestamp;
402         // The timestamp for the latest logTimeoutOverrideEvent calling
403         private long mSendOverrideTimeoutLogTimestamp;
404 
WakefulnessSessionPowerGroup(int powerGroupId)405         public WakefulnessSessionPowerGroup(int powerGroupId) {
406             mCurrentUserActivityEvent = DEFAULT_USER_ACTIVITY;
407             mCurrentUserActivityTimestamp = -1;
408             mPrevUserActivityEvent = DEFAULT_USER_ACTIVITY;
409             mPrevUserActivityTimestamp = -1;
410             mPowerGroupId = powerGroupId;
411             mCurrentScreenPolicy = mPrevScreenPolicy = POLICY_BRIGHT;
412             mCurrentScreenPolicyTimestamp = 0;
413             mPrevScreenPolicyDurationMs = 0;
414             mPastDimDurationMs = 0;
415         }
416 
notifyUserActivity(long eventTime, @PowerManager.UserActivityEvent int event)417         public void notifyUserActivity(long eventTime, @PowerManager.UserActivityEvent int event) {
418             // only track when user activity changes
419             if (event == mCurrentUserActivityEvent) {
420                 return;
421             }
422             mPrevUserActivityEvent = mCurrentUserActivityEvent;
423             mCurrentUserActivityEvent = event;
424             mPrevUserActivityTimestamp = mCurrentUserActivityTimestamp;
425             mCurrentUserActivityTimestamp = eventTime;
426         }
427 
onScreenPolicyUpdate(long eventTime, int newPolicy)428         public void onScreenPolicyUpdate(long eventTime, int newPolicy) {
429             if (newPolicy == mCurrentScreenPolicy) {
430                 return;
431             }
432 
433             if (newPolicy == POLICY_BRIGHT) {
434                 checkAndLogDimIfQualified(POLICY_REASON_BRIGHT_UNDIM, eventTime);
435             }
436 
437             mPrevScreenPolicy = mCurrentScreenPolicy;
438             mCurrentScreenPolicy = newPolicy;
439             mPrevScreenPolicyDurationMs = (int) (eventTime - mCurrentScreenPolicyTimestamp);
440             mCurrentScreenPolicyTimestamp = eventTime;
441         }
442 
onWakefulnessChangeStarted(int wakefulness, int changeReason, long eventTime)443         public void onWakefulnessChangeStarted(int wakefulness, int changeReason, long eventTime) {
444             mCurrentWakefulness = wakefulness;
445             if (mIsInteractive == isInteractive(wakefulness)) {
446                 return;
447             }
448 
449             final int screenOffTimeoutMs = getScreenOffTimeout();
450             mIsInteractive = isInteractive(wakefulness);
451             if (mIsInteractive) {
452                 mInteractiveStateOnStartTimestamp = eventTime;
453 
454                 // Log the outcome of screen timeout override (USER INITIATED REVERT),
455                 // when user initiates to revert the off state in a short period.
456                 if (mTimeoutOffTimestamp != TIMEOUT_OFF_RESET_TIMESTAMP) {
457                     long timeoutOffToOnDurationMs = eventTime - mTimeoutOffTimestamp;
458                     if (timeoutOffToOnDurationMs < USER_INITIATED_REVERT_THRESHOLD_MILLIS) {
459                         mWakefulnessSessionFrameworkStatsLogger.logTimeoutOverrideEvent(
460                                 mPowerGroupId,
461                                 OVERRIDE_OUTCOME_TIMEOUT_USER_INITIATED_REVERT,
462                                 mOverrideTimeoutMs,
463                                 screenOffTimeoutMs);
464                         mSendOverrideTimeoutLogTimestamp = eventTime;
465                     }
466                     mTimeoutOffTimestamp = TIMEOUT_OFF_RESET_TIMESTAMP;
467                 }
468 
469                 checkAndLogDimIfQualified(POLICY_REASON_BRIGHT_INITIATED_REVERT, eventTime);
470 
471             } else {
472                 int lastUserActivity = mCurrentUserActivityEvent;
473                 long lastUserActivityDurationMs = eventTime - mCurrentUserActivityTimestamp;
474                 @OffReason int interactiveStateOffReason = OFF_REASON_UNKNOWN;
475                 int reducedInteractiveStateOnDurationMs = 0;
476                 mInteractiveOffTimestamp = eventTime;
477 
478                 if (changeReason == PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON) {
479                     interactiveStateOffReason = OFF_REASON_POWER_BUTTON;
480 
481                     // Power Off will be triggered by USER_ACTIVITY_EVENT_BUTTON
482                     // The metric wants to record the previous activity before EVENT_BUTTON
483                     lastUserActivity = mPrevUserActivityEvent;
484                     lastUserActivityDurationMs = eventTime - mPrevUserActivityTimestamp;
485 
486                     if (isInOverrideTimeout()
487                             || mTimeoutOverrideReleaseReason == RELEASE_REASON_USER_ACTIVITY_BUTTON
488                     ) {
489                         mWakefulnessSessionFrameworkStatsLogger.logTimeoutOverrideEvent(
490                                 mPowerGroupId,
491                                 OVERRIDE_OUTCOME_CANCEL_POWER_BUTTON,
492                                 mOverrideTimeoutMs,
493                                 screenOffTimeoutMs);
494                         mSendOverrideTimeoutLogTimestamp = eventTime;
495                         mTimeoutOverrideReleaseReason = RELEASE_REASON_UNKNOWN; // reset the reason
496                     }
497 
498                     checkAndLogDimIfQualified(POLICY_REASON_OFF_POWER_BUTTON, eventTime);
499 
500                 } else if (changeReason == PowerManager.GO_TO_SLEEP_REASON_TIMEOUT) {
501                     // Interactive Off reason is timeout
502                     interactiveStateOffReason = OFF_REASON_TIMEOUT;
503 
504                     lastUserActivity = mCurrentUserActivityEvent;
505                     lastUserActivityDurationMs = eventTime - mCurrentUserActivityTimestamp;
506 
507                     // Log the outcome of screen timeout override when the early screen
508                     // timeout has been done successfully.
509                     if (isInOverrideTimeout()) {
510                         reducedInteractiveStateOnDurationMs =
511                                 screenOffTimeoutMs - mOverrideTimeoutMs;
512                         mWakefulnessSessionFrameworkStatsLogger.logTimeoutOverrideEvent(
513                                 mPowerGroupId,
514                                 OVERRIDE_OUTCOME_TIMEOUT_SUCCESS,
515                                 mOverrideTimeoutMs,
516                                 screenOffTimeoutMs);
517                         mSendOverrideTimeoutLogTimestamp = eventTime;
518 
519                         // Record a timestamp to track if the user initiates to revert from off
520                         // state instantly
521                         mTimeoutOffTimestamp = eventTime;
522                     }
523 
524                     checkAndLogDimIfQualified(POLICY_REASON_OFF_TIMEOUT, eventTime);
525                 }
526 
527                 long interactiveStateOnDurationMs =
528                         eventTime - mInteractiveStateOnStartTimestamp;
529 
530                 if (reducedInteractiveStateOnDurationMs < screenOffTimeoutMs
531                         && reducedInteractiveStateOnDurationMs >= 0) {
532                     mWakefulnessSessionFrameworkStatsLogger.logSessionEvent(
533                             mPowerGroupId,
534                             interactiveStateOffReason,
535                             interactiveStateOnDurationMs,
536                             lastUserActivity,
537                             lastUserActivityDurationMs,
538                             reducedInteractiveStateOnDurationMs);
539                 } else {
540                     Slog.w(TAG, "invalid reducedInteractiveStateOnDurationMs: "
541                             + reducedInteractiveStateOnDurationMs);
542                 }
543 
544             }
545         }
546 
acquireTimeoutOverrideWakeLock()547         public void acquireTimeoutOverrideWakeLock() {
548             synchronized (mLock) {
549                 mTimeoutOverrideWakeLockCounter++;
550             }
551         }
552 
releaseTimeoutOverrideWakeLock( @creenTimeoutOverridePolicy.ReleaseReason int releaseReason)553         public void releaseTimeoutOverrideWakeLock(
554                 @ScreenTimeoutOverridePolicy.ReleaseReason  int releaseReason) {
555             synchronized (mLock) {
556                 mTimeoutOverrideWakeLockCounter--;
557             }
558 
559             if (!isInOverrideTimeout()) {
560                 mTimeoutOverrideReleaseReason = releaseReason;
561                 long now = mClock.uptimeMillis();
562 
563                 // Log the outcome of screen timeout override (USER INTERACTIVE or DISCONNECT),
564                 // when early screen timeout be canceled.
565                 // Note: Set the threshold to avoid sending this log repeatly after other outcomes.
566                 long sendOverrideTimeoutLogDuration = now - mSendOverrideTimeoutLogTimestamp;
567                 boolean sendOverrideTimeoutLogSoon = sendOverrideTimeoutLogDuration
568                         < SEND_OVERRIDE_TIMEOUT_LOG_THRESHOLD_MILLIS;
569                 if (!sendOverrideTimeoutLogSoon) {
570                     @OverrideOutcome int outcome = OVERRIDE_OUTCOME_UNKNOWN;
571                     switch (releaseReason) {
572                         case RELEASE_REASON_USER_ACTIVITY_ATTENTION:
573                         case RELEASE_REASON_USER_ACTIVITY_OTHER:
574                         case RELEASE_REASON_USER_ACTIVITY_BUTTON:
575                         case RELEASE_REASON_USER_ACTIVITY_TOUCH:
576                         case RELEASE_REASON_USER_ACTIVITY_ACCESSIBILITY:
577                             outcome = OVERRIDE_OUTCOME_CANCEL_USER_INTERACTION;
578                             break;
579                         case RELEASE_REASON_WAKE_LOCK_DEATH:
580                             outcome = OVERRIDE_OUTCOME_CANCEL_CLIENT_DISCONNECT;
581                             break;
582                         case RELEASE_REASON_NON_INTERACTIVE:
583                         case RELEASE_REASON_SCREEN_LOCK:
584                             outcome = OVERRIDE_OUTCOME_CANCEL_OTHER;
585                             break;
586                         default:
587                             outcome = OVERRIDE_OUTCOME_UNKNOWN;
588                     }
589                     mWakefulnessSessionFrameworkStatsLogger.logTimeoutOverrideEvent(
590                             mPowerGroupId,
591                             outcome,
592                             mOverrideTimeoutMs,
593                             getScreenOffTimeout());
594                 }
595             }
596         }
597 
598         @VisibleForTesting
599         protected boolean isInOverrideTimeout() {
600             synchronized (mLock) {
601                 return (mTimeoutOverrideWakeLockCounter > 0);
602             }
603         }
604 
checkAndLogDimIfQualified( @olicyReason int reasonToBeChecked, long eventTime)605         private void checkAndLogDimIfQualified(
606                 @PolicyReason int reasonToBeChecked, long eventTime) {
607             // Only log dim event when DEFAULT_DISPLAY
608             if (mPowerGroupId != DEFAULT_DISPLAY) {
609                 return;
610             }
611 
612             final int screenOffTimeoutMs = getScreenOffTimeout();
613             int dimDurationMs = 0;
614             int lastUserActivity = mCurrentUserActivityEvent;
615             int lastUserActivityDurationMs = (int) (eventTime - mCurrentUserActivityTimestamp);
616             switch (reasonToBeChecked) {
617                 case POLICY_REASON_OFF_TIMEOUT: {
618                     // The policy ordering:
619                     // (1) --DIM--OFF/DOZE->| or (2) --DIM->| because OFF/DOZE hasn't been updated.
620                     dimDurationMs = (int) (eventTime - mCurrentScreenPolicyTimestamp); //(1)--DIM->|
621                     if (mPrevScreenPolicy == POLICY_DIM) {  // for (2) --DIM--OFF/DOZE->|
622                         dimDurationMs = mPrevScreenPolicyDurationMs;
623                     }
624                     mWakefulnessSessionFrameworkStatsLogger.logDimEvent(
625                             mPhysicalDisplayPortIdForDefaultDisplay,
626                             reasonToBeChecked,
627                             lastUserActivity,
628                             lastUserActivityDurationMs,
629                             dimDurationMs,
630                             screenOffTimeoutMs);
631                     mPastDimDurationMs = dimDurationMs;
632                     return;
633                 }
634                 case POLICY_REASON_OFF_POWER_BUTTON: {
635                     // Power Off will be triggered by USER_ACTIVITY_EVENT_BUTTON
636                     // The metric wants to record the previous activity before EVENT_BUTTON
637                     lastUserActivity = mPrevUserActivityEvent;
638                     lastUserActivityDurationMs = (int) (eventTime - mPrevUserActivityTimestamp);
639                     // the policy ordering:
640                     // (1) ---BRIGHT->| or (2) ---DIM->| because OFF/DOZE hasn't been updated
641                     dimDurationMs = 0; // for (1) ---BRIGHT->| which doesn't have dim (no need log)
642                     if (mCurrentScreenPolicy == POLICY_DIM) { // for (2) ---DIM->|
643                         dimDurationMs = (int) (eventTime - mCurrentScreenPolicyTimestamp);
644                         mWakefulnessSessionFrameworkStatsLogger.logDimEvent(
645                                 mPhysicalDisplayPortIdForDefaultDisplay,
646                                 reasonToBeChecked,
647                                 lastUserActivity,
648                                 lastUserActivityDurationMs,
649                                 dimDurationMs,
650                                 screenOffTimeoutMs);
651                         mHandler.removeCallbacksAndMessages(HANDLER_TOKEN);
652                     }
653 
654                     mPastDimDurationMs = dimDurationMs;
655                     return;
656                 }
657                 case POLICY_REASON_BRIGHT_UNDIM: {
658                     // Has checked the latest screen policy is POLICY_BRIGHT in onScreenPolicyUpdate
659                     if (mCurrentScreenPolicy == POLICY_DIM) { // policy ordering: --DIM--BRIGHT->|
660                         int savedDimDurationMs = (int) (eventTime - mCurrentScreenPolicyTimestamp);
661                         int savedLastUserActivity = lastUserActivity;
662                         int savedLastUserActivityDurationMs = lastUserActivityDurationMs;
663 
664                         // For the undim case --DIM--BRIGHT->|, it needs wait 500 ms to
665                         // differentiate between "power button off" case, which is
666                         // --DIM--BRIGHT(<500ms)--OFF/DOZE->|
667                         // [Method] Wait 500 ms to see whether triggers power button off or not.
668                         // [Reason] We got --DIM--BRIGHT->|. However, if BRIGHT is so short (<500ms)
669                         //          and follows OFF/DOZE, it represents power button off, not undim.
670                         //          It is normal to have a short BRIGHT for power button off because
671                         //          the system need to play an animation before off.
672                         mHandler.postDelayed(() -> {
673                             mWakefulnessSessionFrameworkStatsLogger.logDimEvent(
674                                     mPhysicalDisplayPortIdForDefaultDisplay,
675                                     reasonToBeChecked,
676                                     savedLastUserActivity,
677                                     savedLastUserActivityDurationMs,
678                                     savedDimDurationMs,
679                                     screenOffTimeoutMs);
680                             mPastDimDurationMs = savedDimDurationMs;
681                         }, HANDLER_TOKEN, SCREEN_POLICY_DIM_POWER_OFF_BRIGHT_THRESHOLD_MILLIS);
682                     }
683                     return;
684                 }
685                 case POLICY_REASON_BRIGHT_INITIATED_REVERT: {
686                     // the dimDuration in BRIGHT_INITIATE_REVERT is for the dim duration before
687                     // screen interactive off (mPastDimDurationMs)
688                     long offToOnDurationMs = eventTime - mInteractiveOffTimestamp;
689                     if (mPastDimDurationMs > 0
690                             && offToOnDurationMs < USER_INITIATED_REVERT_THRESHOLD_MILLIS) {
691                         mWakefulnessSessionFrameworkStatsLogger.logDimEvent(
692                                 mPhysicalDisplayPortIdForDefaultDisplay,
693                                 reasonToBeChecked,
694                                 lastUserActivity,
695                                 lastUserActivityDurationMs,
696                                 mPastDimDurationMs,
697                                 screenOffTimeoutMs);
698                     }
699                     return;
700                 }
701                 default:
702                     return;
703             }
704         }
705 
dump(IndentingPrintWriter writer)706         void dump(IndentingPrintWriter writer) {
707             final long now = mClock.uptimeMillis();
708 
709             writer.println("Wakefulness Session Power Group powerGroupId: " + mPowerGroupId);
710             writer.increaseIndent();
711             writer.println("current wakefulness: " + mCurrentWakefulness);
712             writer.println("current user activity event: " + mCurrentUserActivityEvent);
713             final long currentUserActivityDurationMs = now - mCurrentUserActivityTimestamp;
714             writer.println("current user activity duration: " + currentUserActivityDurationMs);
715             writer.println("previous user activity event: " + mPrevUserActivityEvent);
716             final long prevUserActivityDurationMs = now - mPrevUserActivityTimestamp;
717             writer.println("previous user activity duration: " + prevUserActivityDurationMs);
718             writer.println("is in override timeout: " + isInOverrideTimeout());
719             writer.println("mIsInteractive: " + mIsInteractive);
720             writer.println("current screen policy: " + mCurrentScreenPolicy);
721             final long currentScreenPolicyDurationMs = now - mCurrentScreenPolicyTimestamp;
722             writer.println("current screen policy duration: " + currentScreenPolicyDurationMs);
723             writer.println("previous screen policy: " + mPrevScreenPolicy);
724             writer.println("past screen policy duration: " + mPrevScreenPolicyDurationMs);
725             writer.decreaseIndent();
726         }
727     }
728 
729     /** Log screen session atoms */
730     protected static class WakefulnessSessionFrameworkStatsLogger {
logSessionEvent( int powerGroupId, @OffReason int interactiveStateOffReason, long interactiveStateOnDurationMs, @PowerManager.UserActivityEvent int userActivityEvent, long lastUserActivityEventDurationMs, int reducedInteractiveStateOnDurationMs)731         public void logSessionEvent(
732                 int powerGroupId,
733                 @OffReason int interactiveStateOffReason,
734                 long interactiveStateOnDurationMs,
735                 @PowerManager.UserActivityEvent int userActivityEvent,
736                 long lastUserActivityEventDurationMs,
737                 int reducedInteractiveStateOnDurationMs) {
738             int logUserActivityEvent = convertToLogUserActivityEvent(userActivityEvent);
739             FrameworkStatsLog.write(
740                     FrameworkStatsLog.SCREEN_INTERACTIVE_SESSION_REPORTED,
741                     powerGroupId,
742                     interactiveStateOffReason,
743                     interactiveStateOnDurationMs,
744                     logUserActivityEvent,
745                     lastUserActivityEventDurationMs,
746                     (long) reducedInteractiveStateOnDurationMs);
747         }
748 
logTimeoutOverrideEvent( int powerGroupId, @OverrideOutcome int overrideOutcome, int overrideTimeoutMs, int defaultTimeoutMs)749         public void logTimeoutOverrideEvent(
750                 int powerGroupId,
751                 @OverrideOutcome int overrideOutcome,
752                 int overrideTimeoutMs,
753                 int defaultTimeoutMs) {
754             FrameworkStatsLog.write(
755                     FrameworkStatsLog.SCREEN_TIMEOUT_OVERRIDE_REPORTED,
756                     powerGroupId,
757                     overrideOutcome,
758                     (long) overrideTimeoutMs,
759                     (long) defaultTimeoutMs);
760         }
761 
logDimEvent( int physicalDisplayPortId, @PolicyReason int policyReason, @PowerManager.UserActivityEvent int userActivityEvent, int lastUserActivityEventDurationMs, int dimDurationMs, int defaultTimeoutMs)762         public void logDimEvent(
763                 int physicalDisplayPortId,
764                 @PolicyReason int policyReason,
765                 @PowerManager.UserActivityEvent int userActivityEvent,
766                 int lastUserActivityEventDurationMs,
767                 int dimDurationMs,
768                 int defaultTimeoutMs) {
769             int logUserActivityEvent = convertToLogUserActivityEvent(userActivityEvent);
770             FrameworkStatsLog.write(
771                     FrameworkStatsLog.SCREEN_DIM_REPORTED,
772                     physicalDisplayPortId,
773                     policyReason,
774                     logUserActivityEvent,
775                     lastUserActivityEventDurationMs,
776                     dimDurationMs,
777                     defaultTimeoutMs);
778         }
779 
780         private static final int USER_ACTIVITY_OTHER = FrameworkStatsLog
781                 .SCREEN_INTERACTIVE_SESSION_REPORTED__LAST_USER_ACTIVITY_EVENT__OTHER;
782 
783         private static final int USER_ACTIVITY_BUTTON = FrameworkStatsLog
784                 .SCREEN_INTERACTIVE_SESSION_REPORTED__LAST_USER_ACTIVITY_EVENT__BUTTON;
785 
786         private static final int USER_ACTIVITY_TOUCH = FrameworkStatsLog
787                 .SCREEN_INTERACTIVE_SESSION_REPORTED__LAST_USER_ACTIVITY_EVENT__TOUCH;
788 
789         private static final int USER_ACTIVITY_ACCESSIBILITY = FrameworkStatsLog
790                 .SCREEN_INTERACTIVE_SESSION_REPORTED__LAST_USER_ACTIVITY_EVENT__ACCESSIBILITY;
791         private static final int USER_ACTIVITY_ATTENTION = FrameworkStatsLog
792                 .SCREEN_INTERACTIVE_SESSION_REPORTED__LAST_USER_ACTIVITY_EVENT__ATTENTION;
793         private static final int USER_ACTIVITY_FACE_DOWN = FrameworkStatsLog
794                 .SCREEN_INTERACTIVE_SESSION_REPORTED__LAST_USER_ACTIVITY_EVENT__FACE_DOWN;
795 
796         private static final int USER_ACTIVITY_DEVICE_STATE = FrameworkStatsLog
797                 .SCREEN_INTERACTIVE_SESSION_REPORTED__LAST_USER_ACTIVITY_EVENT__DEVICE_STATE;
798 
799         /**
800          * User Activity Event
801          * {@link android.os.statsd.power.ScreenInteractiveSessionReported.UserActivityEvent}.
802          */
803         @IntDef(prefix = {"USER_ACTIVITY_"}, value = {
804                 USER_ACTIVITY_OTHER,
805                 USER_ACTIVITY_BUTTON,
806                 USER_ACTIVITY_TOUCH,
807                 USER_ACTIVITY_ACCESSIBILITY,
808                 USER_ACTIVITY_ATTENTION,
809                 USER_ACTIVITY_FACE_DOWN,
810                 USER_ACTIVITY_DEVICE_STATE,
811         })
812         @Retention(RetentionPolicy.SOURCE)
813         private @interface UserActivityEvent {}
814 
convertToLogUserActivityEvent( @owerManager.UserActivityEvent int userActivity)815         private @UserActivityEvent int convertToLogUserActivityEvent(
816                 @PowerManager.UserActivityEvent int userActivity) {
817             switch (userActivity) {
818                 case PowerManager.USER_ACTIVITY_EVENT_OTHER:
819                     return USER_ACTIVITY_OTHER;
820                 case PowerManager.USER_ACTIVITY_EVENT_BUTTON:
821                     return USER_ACTIVITY_BUTTON;
822                 case PowerManager.USER_ACTIVITY_EVENT_TOUCH:
823                     return USER_ACTIVITY_TOUCH;
824                 case PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY:
825                     return USER_ACTIVITY_ACCESSIBILITY;
826                 case PowerManager.USER_ACTIVITY_EVENT_ATTENTION:
827                     return USER_ACTIVITY_ATTENTION;
828                 case PowerManager.USER_ACTIVITY_EVENT_FACE_DOWN:
829                     return USER_ACTIVITY_FACE_DOWN;
830                 case PowerManager.USER_ACTIVITY_EVENT_DEVICE_STATE:
831                     return USER_ACTIVITY_DEVICE_STATE;
832             }
833             return USER_ACTIVITY_OTHER;
834         }
835     }
836 
837     /** To observe and do actions if users switch */
838     private final class UserSwitchObserver extends SynchronousUserSwitchObserver {
839         @Override
onUserSwitching(int newUserId)840         public void onUserSwitching(int newUserId) throws RemoteException {
841             updateSettingScreenOffTimeout(mContext);
842         }
843     }
844 
845     @VisibleForTesting
846     interface Clock {
uptimeMillis()847         long uptimeMillis();
848     }
849 
850     @VisibleForTesting
851     static class Injector {
getWakefulnessSessionFrameworkStatsLogger()852         WakefulnessSessionFrameworkStatsLogger getWakefulnessSessionFrameworkStatsLogger() {
853             return new WakefulnessSessionFrameworkStatsLogger();
854         }
855 
getClock()856         Clock getClock() {
857             return SystemClock::uptimeMillis;
858         }
859 
getHandler()860         Handler getHandler() {
861             return BackgroundThread.getHandler();
862         }
863 
getDisplayManagerInternal()864         DisplayManagerInternal getDisplayManagerInternal() {
865             return LocalServices.getService(DisplayManagerInternal.class);
866         }
867     }
868 }
869