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.os.PowerManager.USER_ACTIVITY_EVENT_OTHER;
20 import static android.os.PowerManagerInternal.isInteractive;
21 
22 import static com.android.server.power.PowerManagerService.DEFAULT_SCREEN_OFF_TIMEOUT;
23 import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_NON_INTERACTIVE;
24 import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_SCREEN_LOCK;
25 import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_UNKNOWN;
26 import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_USER_ACTIVITY_ACCESSIBILITY;
27 import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_USER_ACTIVITY_ATTENTION;
28 import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_USER_ACTIVITY_BUTTON;
29 import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_USER_ACTIVITY_OTHER;
30 import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_USER_ACTIVITY_TOUCH;
31 
32 import android.annotation.IntDef;
33 import android.app.ActivityManager;
34 import android.app.SynchronousUserSwitchObserver;
35 import android.content.Context;
36 import android.database.ContentObserver;
37 import android.os.Handler;
38 import android.os.PowerManager;
39 import android.os.PowerManagerInternal;
40 import android.os.RemoteException;
41 import android.os.SystemClock;
42 import android.os.UserHandle;
43 import android.provider.Settings;
44 import android.util.IndentingPrintWriter;
45 import android.util.SparseArray;
46 import android.view.Display;
47 
48 import com.android.internal.annotations.VisibleForTesting;
49 import com.android.internal.util.FrameworkStatsLog;
50 
51 import java.io.PrintWriter;
52 import java.lang.annotation.Retention;
53 import java.lang.annotation.RetentionPolicy;
54 
55 /**
56  * Observe the wakefulness session of the device, tracking the reason and the
57  * last user activity when the interactive state is off.
58  */
59 public class WakefulnessSessionObserver {
60     private static final String TAG = "WakefulnessSessionObserver";
61 
62     private static final int OFF_REASON_UNKNOWN = FrameworkStatsLog
63             .SCREEN_INTERACTIVE_SESSION_REPORTED__INTERACTIVE_STATE_OFF_REASON__UNKNOWN;
64     private static final int OFF_REASON_TIMEOUT = FrameworkStatsLog
65             .SCREEN_INTERACTIVE_SESSION_REPORTED__INTERACTIVE_STATE_OFF_REASON__TIMEOUT;
66     @VisibleForTesting
67     protected static final int OFF_REASON_POWER_BUTTON = FrameworkStatsLog
68             .SCREEN_INTERACTIVE_SESSION_REPORTED__INTERACTIVE_STATE_OFF_REASON__POWER_BUTTON;
69 
70     /**
71      * Interactive off reason
72      * {@link android.os.statsd.power.ScreenInteractiveSessionReported.InteractiveStateOffReason}.
73      */
74     @IntDef(prefix = {"OFF_REASON_"}, value = {
75             OFF_REASON_UNKNOWN,
76             OFF_REASON_TIMEOUT,
77             OFF_REASON_POWER_BUTTON
78     })
79     @Retention(RetentionPolicy.SOURCE)
80     private @interface OffReason {}
81 
82     private static final int OVERRIDE_OUTCOME_UNKNOWN = FrameworkStatsLog
83             .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__UNKNOWN;
84     @VisibleForTesting
85     protected static final int OVERRIDE_OUTCOME_TIMEOUT_SUCCESS = FrameworkStatsLog
86             .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__TIMEOUT_SUCCESS;
87     @VisibleForTesting
88     protected static final int OVERRIDE_OUTCOME_TIMEOUT_USER_INITIATED_REVERT = FrameworkStatsLog
89             .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__TIMEOUT_USER_INITIATED_REVERT;
90     private static final int OVERRIDE_OUTCOME_CANCEL_CLIENT_API_CALL = FrameworkStatsLog
91             .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__CANCEL_CLIENT_API_CALL;
92     @VisibleForTesting
93     protected static final int OVERRIDE_OUTCOME_CANCEL_USER_INTERACTION = FrameworkStatsLog
94             .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__CANCEL_USER_INTERACTION;
95     @VisibleForTesting
96     protected static final int OVERRIDE_OUTCOME_CANCEL_POWER_BUTTON = FrameworkStatsLog
97             .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__CANCEL_POWER_BUTTON;
98     private static final int OVERRIDE_OUTCOME_CANCEL_CLIENT_DISCONNECT = FrameworkStatsLog
99             .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__CANCEL_CLIENT_DISCONNECTED;
100     private static final int OVERRIDE_OUTCOME_CANCEL_OTHER = FrameworkStatsLog
101             .SCREEN_TIMEOUT_OVERRIDE_REPORTED__OVERRIDE_OUTCOME__CANCEL_OTHER;
102 
103     /**
104      * Override Outcome
105      * {@link android.os.statsd.power.ScreenTimeoutOverrideReported.OverrideOutcome}.
106      */
107     @IntDef(prefix = {"OVERRIDE_OUTCOME_"}, value = {
108             OVERRIDE_OUTCOME_UNKNOWN,
109             OVERRIDE_OUTCOME_TIMEOUT_SUCCESS,
110             OVERRIDE_OUTCOME_TIMEOUT_USER_INITIATED_REVERT,
111             OVERRIDE_OUTCOME_CANCEL_CLIENT_API_CALL,
112             OVERRIDE_OUTCOME_CANCEL_USER_INTERACTION,
113             OVERRIDE_OUTCOME_CANCEL_POWER_BUTTON,
114             OVERRIDE_OUTCOME_CANCEL_CLIENT_DISCONNECT,
115             OVERRIDE_OUTCOME_CANCEL_OTHER
116     })
117     @Retention(RetentionPolicy.SOURCE)
118     private @interface OverrideOutcome {}
119 
120     private static final int DEFAULT_USER_ACTIVITY = USER_ACTIVITY_EVENT_OTHER;
121     private static final long TIMEOUT_USER_INITIATED_REVERT_THRESHOLD_MILLIS = 5000L;
122     private static final long SEND_OVERRIDE_TIMEOUT_LOG_THRESHOLD_MILLIS = 1000L;
123 
124     private Context mContext;
125     private int mScreenOffTimeoutMs;
126     private int mOverrideTimeoutMs = 0;
127     @VisibleForTesting
128     protected final SparseArray<WakefulnessSessionPowerGroup> mPowerGroups = new SparseArray<>();
129     @VisibleForTesting
130     protected WakefulnessSessionFrameworkStatsLogger mWakefulnessSessionFrameworkStatsLogger;
131     private final Clock mClock;
132     private final Object mLock = new Object();
133 
WakefulnessSessionObserver(Context context, Injector injector)134     public WakefulnessSessionObserver(Context context, Injector injector) {
135         if (injector == null) {
136             injector = new Injector();
137         }
138 
139         mContext = context;
140         mWakefulnessSessionFrameworkStatsLogger = injector
141                 .getWakefulnessSessionFrameworkStatsLogger();
142         mClock = injector.getClock();
143         updateSettingScreenOffTimeout(context);
144 
145         try {
146             final UserSwitchObserver observer = new UserSwitchObserver();
147             ActivityManager.getService().registerUserSwitchObserver(observer, TAG);
148         } catch (RemoteException e) {
149             // Shouldn't happen since in-process.
150         }
151 
152         mOverrideTimeoutMs = mContext.getResources().getInteger(
153                 com.android.internal.R.integer.config_screenTimeoutOverride);
154 
155         mContext.getContentResolver()
156                 .registerContentObserver(
157                         Settings.System.getUriFor(Settings.System.SCREEN_OFF_TIMEOUT),
158                         false,
159                         new ContentObserver(new Handler(mContext.getMainLooper())) {
160                             @Override
161                             public void onChange(boolean selfChange) {
162                                 updateSettingScreenOffTimeout(mContext);
163                             }
164                         },
165                         UserHandle.USER_ALL);
166 
167         mPowerGroups.append(
168                 Display.DEFAULT_DISPLAY_GROUP,
169                 new WakefulnessSessionPowerGroup(Display.DEFAULT_DISPLAY_GROUP));
170     }
171 
172     /**
173      * Track the user activity event.
174      *
175      * @param eventTime Activity time, in uptime millis.
176      * @param powerGroupId Power Group Id for this user activity
177      * @param event Activity type as defined in {@link PowerManager}. {@link
178      *     android.hardware.display.DisplayManagerInternal.DisplayPowerRequest}
179      */
notifyUserActivity( long eventTime, int powerGroupId, @PowerManager.UserActivityEvent int event)180     public void notifyUserActivity(
181             long eventTime, int powerGroupId, @PowerManager.UserActivityEvent int event) {
182         if (!mPowerGroups.contains(powerGroupId)) {
183             mPowerGroups.append(powerGroupId, new WakefulnessSessionPowerGroup(powerGroupId));
184         }
185         mPowerGroups.get(powerGroupId).notifyUserActivity(eventTime, event);
186     }
187 
188     /**
189      * Track the system wakefulness
190      *
191      * @param powerGroupId Power Group Id for this wakefulness changes
192      * @param wakefulness Wakefulness as defined in {@link PowerManagerInternal}
193      * @param changeReason Reason of the go to sleep in
194      * {@link PowerManager.GoToSleepReason} or {@link PowerManager.WakeReason}
195      * @param eventTime timestamp of the wakefulness changes
196      */
onWakefulnessChangeStarted(int powerGroupId, int wakefulness, int changeReason, long eventTime)197     public void onWakefulnessChangeStarted(int powerGroupId, int wakefulness, int changeReason,
198             long eventTime) {
199         if (!mPowerGroups.contains(powerGroupId)) {
200             mPowerGroups.append(powerGroupId, new WakefulnessSessionPowerGroup(powerGroupId));
201         }
202         mPowerGroups.get(powerGroupId).onWakefulnessChangeStarted(wakefulness, changeReason,
203                 eventTime);
204     }
205 
206     /**
207      * Track the acquired wakelocks
208      *
209      * @param flags wakelocks to be acquired {@link PowerManager}
210      */
onWakeLockAcquired(int flags)211     public void onWakeLockAcquired(int flags) {
212         int maskedFlag = flags & PowerManager.WAKE_LOCK_LEVEL_MASK;
213         if (maskedFlag == PowerManager.SCREEN_TIMEOUT_OVERRIDE_WAKE_LOCK) {
214             for (int idx = 0; idx < mPowerGroups.size(); idx++) {
215                 mPowerGroups.valueAt(idx).acquireTimeoutOverrideWakeLock();
216             }
217         }
218     }
219 
220     /**
221      * Track the released wakelocks
222      *
223      * @param flags wakelocks to be released {@link PowerManager}
224      * @param releaseReason the reason to release wakelock
225      * {@link ScreenTimeoutOverridePolicy.ReleaseReason}
226      */
onWakeLockReleased(int flags, int releaseReason)227     public void onWakeLockReleased(int flags, int releaseReason) {
228         int maskedFlag = flags & PowerManager.WAKE_LOCK_LEVEL_MASK;
229         if (maskedFlag == PowerManager.SCREEN_TIMEOUT_OVERRIDE_WAKE_LOCK) {
230             for (int idx = 0; idx < mPowerGroups.size(); idx++) {
231                 mPowerGroups.valueAt(idx).releaseTimeoutOverrideWakeLock(releaseReason);
232             }
233         }
234     }
235 
236     /**
237      * Remove the inactive power group
238      *
239      * @param powerGroupId Power Group Id that should be removed
240      */
removePowerGroup(int powerGroupId)241     public void removePowerGroup(int powerGroupId) {
242         if (mPowerGroups.contains((powerGroupId))) {
243             mPowerGroups.delete(powerGroupId);
244         }
245     }
246 
dump(PrintWriter writer)247     void dump(PrintWriter writer) {
248         writer.println();
249         writer.println("Wakefulness Session Observer:");
250         writer.println("default timeout: " + mScreenOffTimeoutMs);
251         writer.println("override timeout: " + mOverrideTimeoutMs);
252         IndentingPrintWriter indentingPrintWriter = new IndentingPrintWriter(writer);
253         indentingPrintWriter.increaseIndent();
254         for (int idx = 0; idx < mPowerGroups.size(); idx++) {
255             mPowerGroups.valueAt(idx).dump(indentingPrintWriter);
256         }
257         writer.println();
258     }
259 
updateSettingScreenOffTimeout(Context context)260     private void updateSettingScreenOffTimeout(Context context) {
261         synchronized (mLock) {
262             mScreenOffTimeoutMs = Settings.System.getIntForUser(
263                     context.getContentResolver(),
264                     Settings.System.SCREEN_OFF_TIMEOUT,
265                     DEFAULT_SCREEN_OFF_TIMEOUT,
266                     UserHandle.USER_CURRENT);
267         }
268     }
269 
getScreenOffTimeout()270     private int getScreenOffTimeout() {
271         synchronized (mLock) {
272             return mScreenOffTimeoutMs;
273         }
274     }
275 
276     /** Screen Session by each power group */
277     @VisibleForTesting
278     protected class WakefulnessSessionPowerGroup {
279         private static final long TIMEOUT_OFF_RESET_TIMESTAMP = -1;
280 
281         private int mPowerGroupId;
282         private int mCurrentWakefulness;
283         private boolean mIsInteractive = false;
284         // state on start timestamp: will be used in state off to calculate the duration of state on
285         private long mInteractiveStateOnStartTimestamp;
286         @VisibleForTesting
287         protected long mCurrentUserActivityTimestamp;
288         @VisibleForTesting
289         protected @PowerManager.UserActivityEvent int mCurrentUserActivityEvent;
290         @VisibleForTesting
291         protected long mPrevUserActivityTimestamp;
292         @VisibleForTesting
293         protected @PowerManager.UserActivityEvent int mPrevUserActivityEvent;
294         // to track the Override Timeout is set (that is, on SCREEN_TIMEOUT_OVERRIDE_WAKE_LOCK)
295         private int mTimeoutOverrideWakeLockCounter = 0;
296         // The timestamp when Override Timeout is set to false
297         private @ScreenTimeoutOverridePolicy.ReleaseReason int mTimeoutOverrideReleaseReason;
298         // The timestamp when state off by timeout occurs
299         // will set TIMEOUT_OFF_RESET_TIMESTAMP if state on or state off by power button
300         private long mTimeoutOffTimestamp;
301         // The timestamp for the latest logTimeoutOverrideEvent calling
302         private long mSendOverrideTimeoutLogTimestamp;
303 
WakefulnessSessionPowerGroup(int powerGroupId)304         public WakefulnessSessionPowerGroup(int powerGroupId) {
305             mCurrentUserActivityEvent = DEFAULT_USER_ACTIVITY;
306             mCurrentUserActivityTimestamp = -1;
307             mPrevUserActivityEvent = DEFAULT_USER_ACTIVITY;
308             mPrevUserActivityTimestamp = -1;
309             mPowerGroupId = powerGroupId;
310         }
311 
notifyUserActivity(long eventTime, @PowerManager.UserActivityEvent int event)312         public void notifyUserActivity(long eventTime, @PowerManager.UserActivityEvent int event) {
313             // only track when user activity changes
314             if (event == mCurrentUserActivityEvent) {
315                 return;
316             }
317             mPrevUserActivityEvent = mCurrentUserActivityEvent;
318             mCurrentUserActivityEvent = event;
319             mPrevUserActivityTimestamp = mCurrentUserActivityTimestamp;
320             mCurrentUserActivityTimestamp = eventTime;
321         }
322 
onWakefulnessChangeStarted(int wakefulness, int changeReason, long eventTime)323         public void onWakefulnessChangeStarted(int wakefulness, int changeReason, long eventTime) {
324             mCurrentWakefulness = wakefulness;
325             if (mIsInteractive == isInteractive(wakefulness)) {
326                 return;
327             }
328 
329             mIsInteractive = isInteractive(wakefulness);
330             if (mIsInteractive) {
331                 mInteractiveStateOnStartTimestamp = eventTime;
332 
333                 // Log the outcome of screen timeout override (USER INITIATED REVERT),
334                 // when user initiates to revert the screen off state in a short period.
335                 if (mTimeoutOffTimestamp != TIMEOUT_OFF_RESET_TIMESTAMP) {
336                     long offToOnDurationMs = eventTime - mTimeoutOffTimestamp;
337                     if (offToOnDurationMs < TIMEOUT_USER_INITIATED_REVERT_THRESHOLD_MILLIS) {
338                         mWakefulnessSessionFrameworkStatsLogger.logTimeoutOverrideEvent(
339                                 mPowerGroupId,
340                                 OVERRIDE_OUTCOME_TIMEOUT_USER_INITIATED_REVERT,
341                                 mOverrideTimeoutMs,
342                                 getScreenOffTimeout());
343                         mSendOverrideTimeoutLogTimestamp = eventTime;
344                     }
345                     mTimeoutOffTimestamp = TIMEOUT_OFF_RESET_TIMESTAMP;
346                 }
347             } else {
348                 int lastUserActivity = mCurrentUserActivityEvent;
349                 long lastUserActivityDurationMs = eventTime - mCurrentUserActivityTimestamp;
350                 @OffReason int interactiveStateOffReason = OFF_REASON_UNKNOWN;
351                 int reducedInteractiveStateOnDurationMs = 0;
352 
353                 if (changeReason == PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON) {
354                     interactiveStateOffReason = OFF_REASON_POWER_BUTTON;
355 
356                     // Power Off will be triggered by USER_ACTIVITY_EVENT_BUTTON
357                     // The metric wants to record the previous activity before EVENT_BUTTON
358                     lastUserActivity = mPrevUserActivityEvent;
359                     lastUserActivityDurationMs = eventTime - mPrevUserActivityTimestamp;
360 
361                     if (isInOverrideTimeout()
362                             || mTimeoutOverrideReleaseReason == RELEASE_REASON_USER_ACTIVITY_BUTTON
363                     ) {
364                         mWakefulnessSessionFrameworkStatsLogger.logTimeoutOverrideEvent(
365                                 mPowerGroupId,
366                                 OVERRIDE_OUTCOME_CANCEL_POWER_BUTTON,
367                                 mOverrideTimeoutMs,
368                                 getScreenOffTimeout());
369                         mSendOverrideTimeoutLogTimestamp = eventTime;
370                         mTimeoutOverrideReleaseReason = RELEASE_REASON_UNKNOWN; // reset the reason
371                     }
372                 } else if (changeReason == PowerManager.GO_TO_SLEEP_REASON_TIMEOUT) {
373                     // Interactive Off reason is timeout
374                     interactiveStateOffReason = OFF_REASON_TIMEOUT;
375 
376                     lastUserActivity = mCurrentUserActivityEvent;
377                     lastUserActivityDurationMs = eventTime - mCurrentUserActivityTimestamp;
378 
379                     // Log the outcome of screen timeout override when the early screen
380                     // timeout has been done successfully.
381                     if (isInOverrideTimeout()) {
382                         reducedInteractiveStateOnDurationMs =
383                                 getScreenOffTimeout() - mOverrideTimeoutMs;
384 
385                         mWakefulnessSessionFrameworkStatsLogger.logTimeoutOverrideEvent(
386                                 mPowerGroupId,
387                                 OVERRIDE_OUTCOME_TIMEOUT_SUCCESS,
388                                 mOverrideTimeoutMs,
389                                 getScreenOffTimeout());
390                         mSendOverrideTimeoutLogTimestamp = eventTime;
391 
392                         // Record a timestamp to track if the user initiates to revert from off
393                         // state instantly
394                         mTimeoutOffTimestamp = eventTime;
395                     }
396                 }
397 
398                 long interactiveStateOnDurationMs =
399                         eventTime - mInteractiveStateOnStartTimestamp;
400                 mWakefulnessSessionFrameworkStatsLogger.logSessionEvent(
401                         mPowerGroupId,
402                         interactiveStateOffReason,
403                         interactiveStateOnDurationMs,
404                         lastUserActivity,
405                         lastUserActivityDurationMs,
406                         reducedInteractiveStateOnDurationMs);
407             }
408         }
409 
acquireTimeoutOverrideWakeLock()410         public void acquireTimeoutOverrideWakeLock() {
411             synchronized (mLock) {
412                 mTimeoutOverrideWakeLockCounter++;
413             }
414         }
415 
releaseTimeoutOverrideWakeLock( @creenTimeoutOverridePolicy.ReleaseReason int releaseReason)416         public void releaseTimeoutOverrideWakeLock(
417                 @ScreenTimeoutOverridePolicy.ReleaseReason  int releaseReason) {
418             synchronized (mLock) {
419                 mTimeoutOverrideWakeLockCounter--;
420             }
421 
422             if (!isInOverrideTimeout()) {
423                 mTimeoutOverrideReleaseReason = releaseReason;
424                 long now = mClock.uptimeMillis();
425 
426                 // Log the outcome of screen timeout override (USER INTERACTIVE or DISCONNECT),
427                 // when early screen timeout be canceled.
428                 // Note: Set the threshold to avoid sending this log repeatly after other outcomes.
429                 long sendOverrideTimeoutLogDuration = now - mSendOverrideTimeoutLogTimestamp;
430                 boolean sendOverrideTimeoutLogSoon = sendOverrideTimeoutLogDuration
431                         < SEND_OVERRIDE_TIMEOUT_LOG_THRESHOLD_MILLIS;
432                 if (!sendOverrideTimeoutLogSoon) {
433                     @OverrideOutcome int outcome = OVERRIDE_OUTCOME_UNKNOWN;
434                     switch (releaseReason) {
435                         case RELEASE_REASON_USER_ACTIVITY_ATTENTION:
436                         case RELEASE_REASON_USER_ACTIVITY_OTHER:
437                         case RELEASE_REASON_USER_ACTIVITY_BUTTON:
438                         case RELEASE_REASON_USER_ACTIVITY_TOUCH:
439                         case RELEASE_REASON_USER_ACTIVITY_ACCESSIBILITY:
440                             outcome = OVERRIDE_OUTCOME_CANCEL_USER_INTERACTION;
441                             break;
442                         case RELEASE_REASON_SCREEN_LOCK:
443                         case RELEASE_REASON_NON_INTERACTIVE:
444                             outcome = OVERRIDE_OUTCOME_CANCEL_CLIENT_DISCONNECT;
445                             break;
446                         default:
447                             outcome = OVERRIDE_OUTCOME_UNKNOWN;
448                     }
449                     mWakefulnessSessionFrameworkStatsLogger.logTimeoutOverrideEvent(
450                             mPowerGroupId,
451                             outcome,
452                             mOverrideTimeoutMs,
453                             getScreenOffTimeout());
454                 }
455             }
456         }
457 
458         @VisibleForTesting
459         protected boolean isInOverrideTimeout() {
460             synchronized (mLock) {
461                 return (mTimeoutOverrideWakeLockCounter > 0);
462             }
463         }
464 
dump(IndentingPrintWriter writer)465         void dump(IndentingPrintWriter writer) {
466             final long now = mClock.uptimeMillis();
467 
468             writer.println("Wakefulness Session Power Group powerGroupId: " + mPowerGroupId);
469             writer.increaseIndent();
470             writer.println("current wakefulness: " + mCurrentWakefulness);
471             writer.println("current user activity event: " + mCurrentUserActivityEvent);
472             final long currentUserActivityDurationMs = now - mCurrentUserActivityTimestamp;
473             writer.println("current user activity duration: " + currentUserActivityDurationMs);
474             writer.println("previous user activity event: " + mPrevUserActivityEvent);
475             final long prevUserActivityDurationMs = now - mPrevUserActivityTimestamp;
476             writer.println("previous user activity duration: " + prevUserActivityDurationMs);
477             writer.println("is in override timeout: " + isInOverrideTimeout());
478             writer.decreaseIndent();
479         }
480     }
481 
482     /** Log screen session atoms */
483     protected static class WakefulnessSessionFrameworkStatsLogger {
logSessionEvent( int powerGroupId, @OffReason int interactiveStateOffReason, long interactiveStateOnDurationMs, @PowerManager.UserActivityEvent int userActivityEvent, long lastUserActivityEventDurationMs, int reducedInteractiveStateOnDurationMs)484         public void logSessionEvent(
485                 int powerGroupId,
486                 @OffReason int interactiveStateOffReason,
487                 long interactiveStateOnDurationMs,
488                 @PowerManager.UserActivityEvent int userActivityEvent,
489                 long lastUserActivityEventDurationMs,
490                 int reducedInteractiveStateOnDurationMs) {
491             int logUserActivityEvent = convertToLogUserActivityEvent(userActivityEvent);
492             FrameworkStatsLog.write(
493                     FrameworkStatsLog.SCREEN_INTERACTIVE_SESSION_REPORTED,
494                     powerGroupId,
495                     interactiveStateOffReason,
496                     interactiveStateOnDurationMs,
497                     logUserActivityEvent,
498                     lastUserActivityEventDurationMs,
499                     (long) reducedInteractiveStateOnDurationMs);
500         }
501 
logTimeoutOverrideEvent( int powerGroupId, @OverrideOutcome int overrideOutcome, int overrideTimeoutMs, int defaultTimeoutMs)502         public void logTimeoutOverrideEvent(
503                 int powerGroupId,
504                 @OverrideOutcome int overrideOutcome,
505                 int overrideTimeoutMs,
506                 int defaultTimeoutMs) {
507             FrameworkStatsLog.write(
508                     FrameworkStatsLog.SCREEN_TIMEOUT_OVERRIDE_REPORTED,
509                     powerGroupId,
510                     overrideOutcome,
511                     (long) overrideTimeoutMs,
512                     (long) defaultTimeoutMs);
513         }
514 
515         private static final int USER_ACTIVITY_OTHER = FrameworkStatsLog
516                 .SCREEN_INTERACTIVE_SESSION_REPORTED__LAST_USER_ACTIVITY_EVENT__OTHER;
517 
518         private static final int USER_ACTIVITY_BUTTON = FrameworkStatsLog
519                 .SCREEN_INTERACTIVE_SESSION_REPORTED__LAST_USER_ACTIVITY_EVENT__BUTTON;
520 
521         private static final int USER_ACTIVITY_TOUCH = FrameworkStatsLog
522                 .SCREEN_INTERACTIVE_SESSION_REPORTED__LAST_USER_ACTIVITY_EVENT__TOUCH;
523 
524         private static final int USER_ACTIVITY_ACCESSIBILITY = FrameworkStatsLog
525                 .SCREEN_INTERACTIVE_SESSION_REPORTED__LAST_USER_ACTIVITY_EVENT__ACCESSIBILITY;
526         private static final int USER_ACTIVITY_ATTENTION = FrameworkStatsLog
527                 .SCREEN_INTERACTIVE_SESSION_REPORTED__LAST_USER_ACTIVITY_EVENT__ATTENTION;
528         private static final int USER_ACTIVITY_FACE_DOWN = FrameworkStatsLog
529                 .SCREEN_INTERACTIVE_SESSION_REPORTED__LAST_USER_ACTIVITY_EVENT__FACE_DOWN;
530 
531         private static final int USER_ACTIVITY_DEVICE_STATE = FrameworkStatsLog
532                 .SCREEN_INTERACTIVE_SESSION_REPORTED__LAST_USER_ACTIVITY_EVENT__DEVICE_STATE;
533 
534         /**
535          * User Activity Event
536          * {@link android.os.statsd.power.ScreenInteractiveSessionReported.UserActivityEvent}.
537          */
538         @IntDef(prefix = {"USER_ACTIVITY_"}, value = {
539                 USER_ACTIVITY_OTHER,
540                 USER_ACTIVITY_BUTTON,
541                 USER_ACTIVITY_TOUCH,
542                 USER_ACTIVITY_ACCESSIBILITY,
543                 USER_ACTIVITY_ATTENTION,
544                 USER_ACTIVITY_FACE_DOWN,
545                 USER_ACTIVITY_DEVICE_STATE,
546         })
547         @Retention(RetentionPolicy.SOURCE)
548         private @interface UserActivityEvent {}
549 
convertToLogUserActivityEvent( @owerManager.UserActivityEvent int userActivity)550         private @UserActivityEvent int convertToLogUserActivityEvent(
551                 @PowerManager.UserActivityEvent int userActivity) {
552             switch (userActivity) {
553                 case PowerManager.USER_ACTIVITY_EVENT_OTHER:
554                     return USER_ACTIVITY_OTHER;
555                 case PowerManager.USER_ACTIVITY_EVENT_BUTTON:
556                     return USER_ACTIVITY_BUTTON;
557                 case PowerManager.USER_ACTIVITY_EVENT_TOUCH:
558                     return USER_ACTIVITY_TOUCH;
559                 case PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY:
560                     return USER_ACTIVITY_ACCESSIBILITY;
561                 case PowerManager.USER_ACTIVITY_EVENT_ATTENTION:
562                     return USER_ACTIVITY_ATTENTION;
563                 case PowerManager.USER_ACTIVITY_EVENT_FACE_DOWN:
564                     return USER_ACTIVITY_FACE_DOWN;
565                 case PowerManager.USER_ACTIVITY_EVENT_DEVICE_STATE:
566                     return USER_ACTIVITY_DEVICE_STATE;
567             }
568             return USER_ACTIVITY_OTHER;
569         }
570     }
571 
572     /** To observe and do actions if users switch */
573     private final class UserSwitchObserver extends SynchronousUserSwitchObserver {
574         @Override
onUserSwitching(int newUserId)575         public void onUserSwitching(int newUserId) throws RemoteException {
576             updateSettingScreenOffTimeout(mContext);
577         }
578     }
579 
580     @VisibleForTesting
581     interface Clock {
uptimeMillis()582         long uptimeMillis();
583     }
584 
585     @VisibleForTesting
586     static class Injector {
getWakefulnessSessionFrameworkStatsLogger()587         WakefulnessSessionFrameworkStatsLogger getWakefulnessSessionFrameworkStatsLogger() {
588             return new WakefulnessSessionFrameworkStatsLogger();
589         }
590 
getClock()591         Clock getClock() {
592             return SystemClock::uptimeMillis;
593         }
594     }
595 }
596