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