1 /* 2 * Copyright (C) 2014 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.systemui.doze; 18 19 import static android.os.PowerManager.WAKE_REASON_BIOMETRIC; 20 import static android.os.PowerManager.WAKE_REASON_GESTURE; 21 import static android.os.PowerManager.WAKE_REASON_LIFT; 22 import static android.os.PowerManager.WAKE_REASON_PLUGGED_IN; 23 import static android.os.PowerManager.WAKE_REASON_TAP; 24 25 import android.annotation.IntDef; 26 import android.os.PowerManager; 27 import android.util.TimeUtils; 28 29 import androidx.annotation.NonNull; 30 31 import com.android.keyguard.KeyguardUpdateMonitor; 32 import com.android.keyguard.KeyguardUpdateMonitorCallback; 33 import com.android.systemui.Dumpable; 34 import com.android.systemui.dagger.SysUISingleton; 35 import com.android.systemui.dump.DumpManager; 36 import com.android.systemui.statusbar.policy.DevicePostureController; 37 38 import com.google.errorprone.annotations.CompileTimeConstant; 39 40 import java.io.PrintWriter; 41 import java.lang.annotation.Retention; 42 import java.lang.annotation.RetentionPolicy; 43 44 import javax.inject.Inject; 45 46 /** 47 * Logs doze events for debugging and triaging purposes. Logs are dumped in bugreports or on demand: 48 * adb shell dumpsys activity service com.android.systemui/.SystemUIService \ 49 * dependency DumpController DozeLog,DozeStats 50 */ 51 @SysUISingleton 52 public class DozeLog implements Dumpable { 53 private final DozeLogger mLogger; 54 55 private boolean mPulsing; 56 private long mSince; 57 private SummaryStats mPickupPulseNearVibrationStats; 58 private SummaryStats mPickupPulseNotNearVibrationStats; 59 private SummaryStats mNotificationPulseStats; 60 private SummaryStats mScreenOnPulsingStats; 61 private SummaryStats mScreenOnNotPulsingStats; 62 private SummaryStats mEmergencyCallStats; 63 private SummaryStats[][] mProxStats; // [reason][near/far] 64 65 @Inject DozeLog( KeyguardUpdateMonitor keyguardUpdateMonitor, DumpManager dumpManager, DozeLogger logger)66 public DozeLog( 67 KeyguardUpdateMonitor keyguardUpdateMonitor, 68 DumpManager dumpManager, 69 DozeLogger logger) { 70 mLogger = logger; 71 mSince = System.currentTimeMillis(); 72 mPickupPulseNearVibrationStats = new SummaryStats(); 73 mPickupPulseNotNearVibrationStats = new SummaryStats(); 74 mNotificationPulseStats = new SummaryStats(); 75 mScreenOnPulsingStats = new SummaryStats(); 76 mScreenOnNotPulsingStats = new SummaryStats(); 77 mEmergencyCallStats = new SummaryStats(); 78 mProxStats = new SummaryStats[TOTAL_REASONS][2]; 79 for (int i = 0; i < TOTAL_REASONS; i++) { 80 mProxStats[i][0] = new SummaryStats(); 81 mProxStats[i][1] = new SummaryStats(); 82 } 83 84 if (keyguardUpdateMonitor != null) { 85 keyguardUpdateMonitor.registerCallback(mKeyguardCallback); 86 } 87 88 dumpManager.registerDumpable("DumpStats", this); 89 } 90 91 /** 92 * Log debug message to LogBuffer. 93 */ d(@ompileTimeConstant String msg)94 public void d(@CompileTimeConstant String msg) { 95 mLogger.log(msg); 96 } 97 98 /** 99 * Appends pickup wakeup event to the logs 100 */ tracePickupWakeUp(boolean withinVibrationThreshold)101 public void tracePickupWakeUp(boolean withinVibrationThreshold) { 102 mLogger.logPickupWakeup(withinVibrationThreshold); 103 (withinVibrationThreshold ? mPickupPulseNearVibrationStats 104 : mPickupPulseNotNearVibrationStats).append(); 105 } 106 traceSetIgnoreTouchWhilePulsing(boolean ignoreTouch)107 public void traceSetIgnoreTouchWhilePulsing(boolean ignoreTouch) { 108 mLogger.logSetIgnoreTouchWhilePulsing(ignoreTouch); 109 } 110 111 /** 112 * Appends pulse started event to the logs. 113 * @param reason why the pulse started 114 */ tracePulseStart(@eason int reason)115 public void tracePulseStart(@Reason int reason) { 116 mLogger.logPulseStart(reason); 117 mPulsing = true; 118 } 119 120 /** 121 * Appends pulse finished event to the logs 122 */ tracePulseFinish()123 public void tracePulseFinish() { 124 mLogger.logPulseFinish(); 125 mPulsing = false; 126 } 127 128 /** 129 * Appends pulse event to the logs 130 */ traceNotificationPulse()131 public void traceNotificationPulse() { 132 mLogger.logNotificationPulse(); 133 mNotificationPulseStats.append(); 134 } 135 136 /** 137 * Appends dozing event to the logs. Logs current dozing state when entering/exiting AOD. 138 * @param dozing true if dozing, else false 139 */ traceDozing(boolean dozing)140 public void traceDozing(boolean dozing) { 141 mLogger.logDozing(dozing); 142 mPulsing = false; 143 } 144 145 /** 146 * Appends dozing event to the logs when dozing has changed in AOD. 147 * @param dozing true if we're now dozing, else false 148 */ traceDozingChanged(boolean dozing)149 public void traceDozingChanged(boolean dozing) { 150 mLogger.logDozingChanged(dozing); 151 } 152 153 /** 154 * Appends fling event to the logs 155 */ traceFling(boolean expand, boolean aboveThreshold, boolean screenOnFromTouch)156 public void traceFling(boolean expand, boolean aboveThreshold, 157 boolean screenOnFromTouch) { 158 mLogger.logFling(expand, aboveThreshold, screenOnFromTouch); 159 } 160 161 /** 162 * Appends emergency call event to the logs 163 */ traceEmergencyCall()164 public void traceEmergencyCall() { 165 mLogger.logEmergencyCall(); 166 mEmergencyCallStats.append(); 167 } 168 169 /** 170 * Appends keyguard bouncer changed event to the logs 171 * @param showing true if the keyguard bouncer is showing, else false 172 */ traceKeyguardBouncerChanged(boolean showing)173 public void traceKeyguardBouncerChanged(boolean showing) { 174 mLogger.logKeyguardBouncerChanged(showing); 175 } 176 177 /** 178 * Appends screen-on event to the logs 179 */ traceScreenOn()180 public void traceScreenOn() { 181 mLogger.logScreenOn(mPulsing); 182 (mPulsing ? mScreenOnPulsingStats : mScreenOnNotPulsingStats).append(); 183 mPulsing = false; 184 } 185 186 /** 187 * Appends screen-off event to the logs 188 * @param why reason the screen is off 189 */ traceScreenOff(int why)190 public void traceScreenOff(int why) { 191 mLogger.logScreenOff(why); 192 } 193 194 /** 195 * Appends missed tick event to the logs 196 * @param delay of the missed tick 197 */ traceMissedTick(String delay)198 public void traceMissedTick(String delay) { 199 mLogger.logMissedTick(delay); 200 } 201 202 /** 203 * Appends time tick scheduled event to the logs 204 * @param when time tick scheduled at 205 * @param triggerAt time tick trigger at 206 */ traceTimeTickScheduled(long when, long triggerAt)207 public void traceTimeTickScheduled(long when, long triggerAt) { 208 mLogger.logTimeTickScheduled(when, triggerAt); 209 } 210 211 /** 212 * Logs cancelation requests for time ticks 213 * @param isPending is an unschedule request pending? 214 * @param isTimeTickScheduled is a time tick request scheduled 215 */ tracePendingUnscheduleTimeTick(boolean isPending, boolean isTimeTickScheduled)216 public void tracePendingUnscheduleTimeTick(boolean isPending, boolean isTimeTickScheduled) { 217 mLogger.logPendingUnscheduleTimeTick(isPending, isTimeTickScheduled); 218 } 219 220 /** 221 * Appends keyguard visibility change event to the logs 222 * @param showing whether the keyguard is now showing 223 */ traceKeyguard(boolean showing)224 public void traceKeyguard(boolean showing) { 225 mLogger.logKeyguardVisibilityChange(showing); 226 if (!showing) mPulsing = false; 227 } 228 229 /** 230 * Appends doze state changed event to the logs 231 * @param state new DozeMachine state 232 */ traceState(DozeMachine.State state)233 public void traceState(DozeMachine.State state) { 234 mLogger.logDozeStateChanged(state); 235 } 236 237 /** 238 * Appends doze state changed sent to all DozeMachine parts event to the logs 239 * @param state new DozeMachine state 240 */ traceDozeStateSendComplete(DozeMachine.State state)241 public void traceDozeStateSendComplete(DozeMachine.State state) { 242 mLogger.logStateChangedSent(state); 243 } 244 245 /** 246 * Appends display state delayed by UDFPS event to the logs 247 * @param delayedDisplayState the display screen state that was delayed 248 */ traceDisplayStateDelayedByUdfps(int delayedDisplayState)249 public void traceDisplayStateDelayedByUdfps(int delayedDisplayState) { 250 mLogger.logDisplayStateDelayedByUdfps(delayedDisplayState); 251 } 252 253 /** 254 * Appends display state changed event to the logs 255 * @param displayState new DozeMachine state 256 * @param afterRequest whether the request has successfully been sent else false for it's 257 * about to be requested 258 */ traceDisplayState(int displayState, boolean afterRequest)259 public void traceDisplayState(int displayState, boolean afterRequest) { 260 mLogger.logDisplayStateChanged(displayState, afterRequest); 261 } 262 263 /** 264 * Appends wake-display event to the logs. 265 * @param wake if we're waking up or sleeping. 266 */ traceWakeDisplay(boolean wake, @Reason int reason)267 public void traceWakeDisplay(boolean wake, @Reason int reason) { 268 mLogger.logWakeDisplay(wake, reason); 269 } 270 271 /** 272 * Appends proximity result event to the logs 273 * @param near true if near, else false 274 * @param reason why proximity result was triggered 275 */ traceProximityResult(boolean near, long millis, @Reason int reason)276 public void traceProximityResult(boolean near, long millis, @Reason int reason) { 277 mLogger.logProximityResult(near, millis, reason); 278 mProxStats[reason][near ? 0 : 1].append(); 279 } 280 281 @Override dump(@onNull PrintWriter pw, @NonNull String[] args)282 public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { 283 synchronized (DozeLog.class) { 284 pw.print(" Doze summary stats (for "); 285 TimeUtils.formatDuration(System.currentTimeMillis() - mSince, pw); 286 pw.println("):"); 287 mPickupPulseNearVibrationStats.dump(pw, "Pickup pulse (near vibration)"); 288 mPickupPulseNotNearVibrationStats.dump(pw, "Pickup pulse (not near vibration)"); 289 mNotificationPulseStats.dump(pw, "Notification pulse"); 290 mScreenOnPulsingStats.dump(pw, "Screen on (pulsing)"); 291 mScreenOnNotPulsingStats.dump(pw, "Screen on (not pulsing)"); 292 mEmergencyCallStats.dump(pw, "Emergency call"); 293 for (int i = 0; i < TOTAL_REASONS; i++) { 294 final String reason = reasonToString(i); 295 mProxStats[i][0].dump(pw, "Proximity near (" + reason + ")"); 296 mProxStats[i][1].dump(pw, "Proximity far (" + reason + ")"); 297 } 298 } 299 } 300 301 /** 302 * Appends doze updates due to a posture change. 303 */ tracePostureChanged( @evicePostureController.DevicePostureInt int posture, String partUpdated )304 public void tracePostureChanged( 305 @DevicePostureController.DevicePostureInt int posture, 306 String partUpdated 307 ) { 308 mLogger.logPostureChanged(posture, partUpdated); 309 } 310 311 /** 312 * Appends pulse dropped event to logs 313 */ tracePulseDropped(String from, DozeMachine.State state)314 public void tracePulseDropped(String from, DozeMachine.State state) { 315 mLogger.logPulseDropped(from, state); 316 } 317 318 /** 319 * Appends sensor event dropped event to logs 320 */ traceSensorEventDropped(@eason int pulseReason, String reason)321 public void traceSensorEventDropped(@Reason int pulseReason, String reason) { 322 mLogger.logSensorEventDropped(pulseReason, reason); 323 } 324 325 /** 326 * Appends pulsing event to logs. 327 */ tracePulseEvent(String pulseEvent, boolean dozing, int pulseReason)328 public void tracePulseEvent(String pulseEvent, boolean dozing, int pulseReason) { 329 mLogger.logPulseEvent(pulseEvent, dozing, DozeLog.reasonToString(pulseReason)); 330 } 331 332 /** 333 * Appends pulse dropped event to logs 334 * @param reason why the pulse was dropped 335 */ tracePulseDropped(String reason)336 public void tracePulseDropped(String reason) { 337 mLogger.logPulseDropped(reason); 338 } 339 340 /** 341 * Appends pulse touch displayed by prox sensor event to logs 342 * @param disabled 343 */ tracePulseTouchDisabledByProx(boolean disabled)344 public void tracePulseTouchDisabledByProx(boolean disabled) { 345 mLogger.logPulseTouchDisabledByProx(disabled); 346 } 347 348 /** 349 * Appends sensor triggered event to logs 350 * @param reason why the sensor was triggered 351 */ traceSensor(@eason int reason)352 public void traceSensor(@Reason int reason) { 353 mLogger.logSensorTriggered(reason); 354 } 355 356 /** 357 * Appends the doze state that was suppressed to the doze event log 358 * @param suppressedState The {@link DozeMachine.State} that was suppressed 359 * @param reason what suppressed always on 360 */ traceAlwaysOnSuppressed(DozeMachine.State suppressedState, String reason)361 public void traceAlwaysOnSuppressed(DozeMachine.State suppressedState, String reason) { 362 mLogger.logAlwaysOnSuppressed(suppressedState, reason); 363 } 364 365 /** 366 * Appends reason why doze immediately ended. 367 */ traceImmediatelyEndDoze(String reason)368 public void traceImmediatelyEndDoze(String reason) { 369 mLogger.logImmediatelyEndDoze(reason); 370 } 371 372 /** 373 * Logs the car mode started event. 374 */ traceCarModeStarted()375 public void traceCarModeStarted() { 376 mLogger.logCarModeStarted(); 377 } 378 379 /** 380 * Logs the car mode ended event. 381 */ traceCarModeEnded()382 public void traceCarModeEnded() { 383 mLogger.logCarModeEnded(); 384 } 385 386 /** 387 * Appends power save changes that may cause a new doze state 388 * @param powerSaveActive true if power saving is active 389 * @param nextState the state that we'll transition to 390 */ tracePowerSaveChanged(boolean powerSaveActive, DozeMachine.State nextState)391 public void tracePowerSaveChanged(boolean powerSaveActive, DozeMachine.State nextState) { 392 mLogger.logPowerSaveChanged(powerSaveActive, nextState); 393 } 394 395 /** 396 * Appends an event on AOD suppression change 397 * @param suppressed true if AOD is being suppressed 398 * @param nextState the state that we'll transition to 399 */ traceAlwaysOnSuppressedChange(boolean suppressed, DozeMachine.State nextState)400 public void traceAlwaysOnSuppressedChange(boolean suppressed, DozeMachine.State nextState) { 401 mLogger.logAlwaysOnSuppressedChange(suppressed, nextState); 402 } 403 404 /** 405 * Appends new AOD screen brightness to logs 406 * @param brightness display brightness setting between 1 and 255 407 * @param afterRequest whether the request has successfully been sent else false for it's 408 * about to be requested 409 */ traceDozeScreenBrightness(int brightness, boolean afterRequest)410 public void traceDozeScreenBrightness(int brightness, boolean afterRequest) { 411 mLogger.logDozeScreenBrightness(brightness, afterRequest); 412 } 413 414 /** 415 * Appends new AOD screen brightness to logs 416 * @param brightness display brightness setting between {@link PowerManager#BRIGHTNESS_MIN} and 417 * {@link PowerManager#BRIGHTNESS_MAX} 418 * @param afterRequest whether the request has successfully been sent else false for it's 419 * about to be requested 420 */ traceDozeScreenBrightnessFloat(float brightness, boolean afterRequest)421 public void traceDozeScreenBrightnessFloat(float brightness, boolean afterRequest) { 422 mLogger.logDozeScreenBrightnessFloat(brightness, afterRequest); 423 } 424 425 /** 426 * Appends new AOD dimming scrim opacity to logs 427 * @param scrimOpacity 428 */ traceSetAodDimmingScrim(float scrimOpacity)429 public void traceSetAodDimmingScrim(float scrimOpacity) { 430 mLogger.logSetAodDimmingScrim((long) scrimOpacity); 431 } 432 433 /** 434 * Appends sensor attempted to register and whether it was a successful registration. 435 */ traceSensorRegisterAttempt(String sensorName, boolean successfulRegistration)436 public void traceSensorRegisterAttempt(String sensorName, boolean successfulRegistration) { 437 mLogger.logSensorRegisterAttempt(sensorName, successfulRegistration); 438 } 439 440 /** 441 * Appends sensor attempted to unregister and whether it was successfully unregistered. 442 */ traceSensorUnregisterAttempt(String sensorInfo, boolean successfullyUnregistered)443 public void traceSensorUnregisterAttempt(String sensorInfo, boolean successfullyUnregistered) { 444 mLogger.logSensorUnregisterAttempt(sensorInfo, successfullyUnregistered); 445 } 446 447 /** 448 * Appends sensor attempted to unregister and whether it was successfully unregistered 449 * with a reason the sensor is being unregistered. 450 */ traceSensorUnregisterAttempt(String sensorInfo, boolean successfullyUnregistered, String reason)451 public void traceSensorUnregisterAttempt(String sensorInfo, boolean successfullyUnregistered, 452 String reason) { 453 mLogger.logSensorUnregisterAttempt(sensorInfo, successfullyUnregistered, reason); 454 } 455 456 /** 457 * Appends the event of skipping a sensor registration since it's already registered. 458 */ traceSkipRegisterSensor(String sensorInfo)459 public void traceSkipRegisterSensor(String sensorInfo) { 460 mLogger.logSkipSensorRegistration(sensorInfo); 461 } 462 463 /** 464 * Appends a plugin sensor was registered or unregistered event. 465 */ tracePluginSensorUpdate(boolean registered)466 public void tracePluginSensorUpdate(boolean registered) { 467 if (registered) { 468 mLogger.log("register plugin sensor"); 469 } else { 470 mLogger.log("unregister plugin sensor"); 471 } 472 } 473 474 private class SummaryStats { 475 private int mCount; 476 append()477 public void append() { 478 mCount++; 479 } 480 dump(PrintWriter pw, String type)481 public void dump(PrintWriter pw, String type) { 482 if (mCount == 0) return; 483 pw.print(" "); 484 pw.print(type); 485 pw.print(": n="); 486 pw.print(mCount); 487 pw.print(" ("); 488 final double perHr = (double) mCount / (System.currentTimeMillis() - mSince) 489 * 1000 * 60 * 60; 490 pw.print(perHr); 491 pw.print("/hr)"); 492 pw.println(); 493 } 494 } 495 496 private final KeyguardUpdateMonitorCallback mKeyguardCallback = 497 new KeyguardUpdateMonitorCallback() { 498 @Override 499 public void onEmergencyCallAction() { 500 traceEmergencyCall(); 501 } 502 503 @Override 504 public void onKeyguardBouncerFullyShowingChanged(boolean fullyShowing) { 505 traceKeyguardBouncerChanged(fullyShowing); 506 } 507 508 @Override 509 public void onStartedWakingUp() { 510 traceScreenOn(); 511 } 512 513 @Override 514 public void onFinishedGoingToSleep(int why) { 515 traceScreenOff(why); 516 } 517 518 @Override 519 public void onKeyguardVisibilityChanged(boolean visible) { 520 traceKeyguard(visible); 521 } 522 }; 523 524 /** 525 * Converts the reason (integer) to a user-readable string 526 */ reasonToString(@eason int pulseReason)527 public static String reasonToString(@Reason int pulseReason) { 528 switch (pulseReason) { 529 case PULSE_REASON_INTENT: return "intent"; 530 case PULSE_REASON_NOTIFICATION: return "notification"; 531 case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion"; 532 case REASON_SENSOR_PICKUP: return "pickup"; 533 case REASON_SENSOR_DOUBLE_TAP: return "doubletap"; 534 case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress"; 535 case PULSE_REASON_DOCKING: return "docking"; 536 case PULSE_REASON_SENSOR_WAKE_REACH: return "reach-wakelockscreen"; 537 case REASON_SENSOR_WAKE_UP_PRESENCE: return "presence-wakeup"; 538 case REASON_SENSOR_TAP: return "tap"; 539 case REASON_SENSOR_UDFPS_LONG_PRESS: return "udfps"; 540 case REASON_SENSOR_QUICK_PICKUP: return "quickPickup"; 541 case PULSE_REASON_FINGERPRINT_ACTIVATED: return "fingerprint-triggered"; 542 default: throw new IllegalArgumentException("invalid reason: " + pulseReason); 543 } 544 } 545 546 /** 547 * Converts {@link Reason} to {@link PowerManager.WakeReason}. 548 */ getPowerManagerWakeReason(@eason int wakeReason)549 public static @PowerManager.WakeReason int getPowerManagerWakeReason(@Reason int wakeReason) { 550 switch (wakeReason) { 551 case REASON_SENSOR_DOUBLE_TAP: 552 case REASON_SENSOR_TAP: 553 return WAKE_REASON_TAP; 554 case REASON_SENSOR_PICKUP: 555 return WAKE_REASON_LIFT; 556 case REASON_SENSOR_UDFPS_LONG_PRESS: 557 return WAKE_REASON_BIOMETRIC; 558 case PULSE_REASON_DOCKING: 559 return WAKE_REASON_PLUGGED_IN; 560 default: 561 return WAKE_REASON_GESTURE; 562 } 563 } 564 565 @Retention(RetentionPolicy.SOURCE) 566 @IntDef({PULSE_REASON_NONE, PULSE_REASON_INTENT, PULSE_REASON_NOTIFICATION, 567 PULSE_REASON_SENSOR_SIGMOTION, REASON_SENSOR_PICKUP, REASON_SENSOR_DOUBLE_TAP, 568 PULSE_REASON_SENSOR_LONG_PRESS, PULSE_REASON_DOCKING, REASON_SENSOR_WAKE_UP_PRESENCE, 569 PULSE_REASON_SENSOR_WAKE_REACH, REASON_SENSOR_TAP, 570 REASON_SENSOR_UDFPS_LONG_PRESS, REASON_SENSOR_QUICK_PICKUP, 571 PULSE_REASON_FINGERPRINT_ACTIVATED 572 }) 573 public @interface Reason {} 574 public static final int PULSE_REASON_NONE = -1; 575 public static final int PULSE_REASON_INTENT = 0; 576 public static final int PULSE_REASON_NOTIFICATION = 1; 577 public static final int PULSE_REASON_SENSOR_SIGMOTION = 2; 578 public static final int REASON_SENSOR_PICKUP = 3; 579 public static final int REASON_SENSOR_DOUBLE_TAP = 4; 580 public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5; 581 public static final int PULSE_REASON_DOCKING = 6; 582 public static final int REASON_SENSOR_WAKE_UP_PRESENCE = 7; 583 public static final int PULSE_REASON_SENSOR_WAKE_REACH = 8; 584 public static final int REASON_SENSOR_TAP = 9; 585 public static final int REASON_SENSOR_UDFPS_LONG_PRESS = 10; 586 public static final int REASON_SENSOR_QUICK_PICKUP = 11; 587 public static final int PULSE_REASON_FINGERPRINT_ACTIVATED = 12; 588 589 public static final int TOTAL_REASONS = 13; 590 } 591