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 * Appends keyguard visibility change event to the logs 213 * @param showing whether the keyguard is now showing 214 */ traceKeyguard(boolean showing)215 public void traceKeyguard(boolean showing) { 216 mLogger.logKeyguardVisibilityChange(showing); 217 if (!showing) mPulsing = false; 218 } 219 220 /** 221 * Appends doze state changed event to the logs 222 * @param state new DozeMachine state 223 */ traceState(DozeMachine.State state)224 public void traceState(DozeMachine.State state) { 225 mLogger.logDozeStateChanged(state); 226 } 227 228 /** 229 * Appends doze state changed sent to all DozeMachine parts event to the logs 230 * @param state new DozeMachine state 231 */ traceDozeStateSendComplete(DozeMachine.State state)232 public void traceDozeStateSendComplete(DozeMachine.State state) { 233 mLogger.logStateChangedSent(state); 234 } 235 236 /** 237 * Appends display state delayed by UDFPS event to the logs 238 * @param delayedDisplayState the display screen state that was delayed 239 */ traceDisplayStateDelayedByUdfps(int delayedDisplayState)240 public void traceDisplayStateDelayedByUdfps(int delayedDisplayState) { 241 mLogger.logDisplayStateDelayedByUdfps(delayedDisplayState); 242 } 243 244 /** 245 * Appends display state changed event to the logs 246 * @param displayState new DozeMachine state 247 */ traceDisplayState(int displayState)248 public void traceDisplayState(int displayState) { 249 mLogger.logDisplayStateChanged(displayState); 250 } 251 252 /** 253 * Appends wake-display event to the logs. 254 * @param wake if we're waking up or sleeping. 255 */ traceWakeDisplay(boolean wake, @Reason int reason)256 public void traceWakeDisplay(boolean wake, @Reason int reason) { 257 mLogger.logWakeDisplay(wake, reason); 258 } 259 260 /** 261 * Appends proximity result event to the logs 262 * @param near true if near, else false 263 * @param reason why proximity result was triggered 264 */ traceProximityResult(boolean near, long millis, @Reason int reason)265 public void traceProximityResult(boolean near, long millis, @Reason int reason) { 266 mLogger.logProximityResult(near, millis, reason); 267 mProxStats[reason][near ? 0 : 1].append(); 268 } 269 270 @Override dump(@onNull PrintWriter pw, @NonNull String[] args)271 public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { 272 synchronized (DozeLog.class) { 273 pw.print(" Doze summary stats (for "); 274 TimeUtils.formatDuration(System.currentTimeMillis() - mSince, pw); 275 pw.println("):"); 276 mPickupPulseNearVibrationStats.dump(pw, "Pickup pulse (near vibration)"); 277 mPickupPulseNotNearVibrationStats.dump(pw, "Pickup pulse (not near vibration)"); 278 mNotificationPulseStats.dump(pw, "Notification pulse"); 279 mScreenOnPulsingStats.dump(pw, "Screen on (pulsing)"); 280 mScreenOnNotPulsingStats.dump(pw, "Screen on (not pulsing)"); 281 mEmergencyCallStats.dump(pw, "Emergency call"); 282 for (int i = 0; i < TOTAL_REASONS; i++) { 283 final String reason = reasonToString(i); 284 mProxStats[i][0].dump(pw, "Proximity near (" + reason + ")"); 285 mProxStats[i][1].dump(pw, "Proximity far (" + reason + ")"); 286 } 287 } 288 } 289 290 /** 291 * Appends doze updates due to a posture change. 292 */ tracePostureChanged( @evicePostureController.DevicePostureInt int posture, String partUpdated )293 public void tracePostureChanged( 294 @DevicePostureController.DevicePostureInt int posture, 295 String partUpdated 296 ) { 297 mLogger.logPostureChanged(posture, partUpdated); 298 } 299 300 /** 301 * Appends pulse dropped event to logs 302 */ tracePulseDropped(String from, DozeMachine.State state)303 public void tracePulseDropped(String from, DozeMachine.State state) { 304 mLogger.logPulseDropped(from, state); 305 } 306 307 /** 308 * Appends sensor event dropped event to logs 309 */ traceSensorEventDropped(@eason int pulseReason, String reason)310 public void traceSensorEventDropped(@Reason int pulseReason, String reason) { 311 mLogger.logSensorEventDropped(pulseReason, reason); 312 } 313 314 /** 315 * Appends pulsing event to logs. 316 */ tracePulseEvent(String pulseEvent, boolean dozing, int pulseReason)317 public void tracePulseEvent(String pulseEvent, boolean dozing, int pulseReason) { 318 mLogger.logPulseEvent(pulseEvent, dozing, DozeLog.reasonToString(pulseReason)); 319 } 320 321 /** 322 * Appends pulse dropped event to logs 323 * @param reason why the pulse was dropped 324 */ tracePulseDropped(String reason)325 public void tracePulseDropped(String reason) { 326 mLogger.logPulseDropped(reason); 327 } 328 329 /** 330 * Appends pulse touch displayed by prox sensor event to logs 331 * @param disabled 332 */ tracePulseTouchDisabledByProx(boolean disabled)333 public void tracePulseTouchDisabledByProx(boolean disabled) { 334 mLogger.logPulseTouchDisabledByProx(disabled); 335 } 336 337 /** 338 * Appends sensor triggered event to logs 339 * @param reason why the sensor was triggered 340 */ traceSensor(@eason int reason)341 public void traceSensor(@Reason int reason) { 342 mLogger.logSensorTriggered(reason); 343 } 344 345 /** 346 * Appends the doze state that was suppressed to the doze event log 347 * @param suppressedState The {@link DozeMachine.State} that was suppressed 348 * @param reason what suppressed always on 349 */ traceAlwaysOnSuppressed(DozeMachine.State suppressedState, String reason)350 public void traceAlwaysOnSuppressed(DozeMachine.State suppressedState, String reason) { 351 mLogger.logAlwaysOnSuppressed(suppressedState, reason); 352 } 353 354 /** 355 * Appends reason why doze immediately ended. 356 */ traceImmediatelyEndDoze(String reason)357 public void traceImmediatelyEndDoze(String reason) { 358 mLogger.logImmediatelyEndDoze(reason); 359 } 360 361 /** 362 * Logs the car mode started event. 363 */ traceCarModeStarted()364 public void traceCarModeStarted() { 365 mLogger.logCarModeStarted(); 366 } 367 368 /** 369 * Logs the car mode ended event. 370 */ traceCarModeEnded()371 public void traceCarModeEnded() { 372 mLogger.logCarModeEnded(); 373 } 374 375 /** 376 * Appends power save changes that may cause a new doze state 377 * @param powerSaveActive true if power saving is active 378 * @param nextState the state that we'll transition to 379 */ tracePowerSaveChanged(boolean powerSaveActive, DozeMachine.State nextState)380 public void tracePowerSaveChanged(boolean powerSaveActive, DozeMachine.State nextState) { 381 mLogger.logPowerSaveChanged(powerSaveActive, nextState); 382 } 383 384 /** 385 * Appends an event on AOD suppression change 386 * @param suppressed true if AOD is being suppressed 387 * @param nextState the state that we'll transition to 388 */ traceAlwaysOnSuppressedChange(boolean suppressed, DozeMachine.State nextState)389 public void traceAlwaysOnSuppressedChange(boolean suppressed, DozeMachine.State nextState) { 390 mLogger.logAlwaysOnSuppressedChange(suppressed, nextState); 391 } 392 393 /** 394 * Appends new AOD screen brightness to logs 395 * @param brightness display brightness setting 396 */ traceDozeScreenBrightness(int brightness)397 public void traceDozeScreenBrightness(int brightness) { 398 mLogger.logDozeScreenBrightness(brightness); 399 } 400 401 /** 402 * Appends new AOD dimming scrim opacity to logs 403 * @param scrimOpacity 404 */ traceSetAodDimmingScrim(float scrimOpacity)405 public void traceSetAodDimmingScrim(float scrimOpacity) { 406 mLogger.logSetAodDimmingScrim((long) scrimOpacity); 407 } 408 409 /** 410 * Appends sensor attempted to register and whether it was a successful registration. 411 */ traceSensorRegisterAttempt(String sensorName, boolean successfulRegistration)412 public void traceSensorRegisterAttempt(String sensorName, boolean successfulRegistration) { 413 mLogger.logSensorRegisterAttempt(sensorName, successfulRegistration); 414 } 415 416 /** 417 * Appends sensor attempted to unregister and whether it was successfully unregistered. 418 */ traceSensorUnregisterAttempt(String sensorInfo, boolean successfullyUnregistered)419 public void traceSensorUnregisterAttempt(String sensorInfo, boolean successfullyUnregistered) { 420 mLogger.logSensorUnregisterAttempt(sensorInfo, successfullyUnregistered); 421 } 422 423 /** 424 * Appends sensor attempted to unregister and whether it was successfully unregistered 425 * with a reason the sensor is being unregistered. 426 */ traceSensorUnregisterAttempt(String sensorInfo, boolean successfullyUnregistered, String reason)427 public void traceSensorUnregisterAttempt(String sensorInfo, boolean successfullyUnregistered, 428 String reason) { 429 mLogger.logSensorUnregisterAttempt(sensorInfo, successfullyUnregistered, reason); 430 } 431 432 /** 433 * Appends the event of skipping a sensor registration since it's already registered. 434 */ traceSkipRegisterSensor(String sensorInfo)435 public void traceSkipRegisterSensor(String sensorInfo) { 436 mLogger.logSkipSensorRegistration(sensorInfo); 437 } 438 439 /** 440 * Appends a plugin sensor was registered or unregistered event. 441 */ tracePluginSensorUpdate(boolean registered)442 public void tracePluginSensorUpdate(boolean registered) { 443 if (registered) { 444 mLogger.log("register plugin sensor"); 445 } else { 446 mLogger.log("unregister plugin sensor"); 447 } 448 } 449 450 private class SummaryStats { 451 private int mCount; 452 append()453 public void append() { 454 mCount++; 455 } 456 dump(PrintWriter pw, String type)457 public void dump(PrintWriter pw, String type) { 458 if (mCount == 0) return; 459 pw.print(" "); 460 pw.print(type); 461 pw.print(": n="); 462 pw.print(mCount); 463 pw.print(" ("); 464 final double perHr = (double) mCount / (System.currentTimeMillis() - mSince) 465 * 1000 * 60 * 60; 466 pw.print(perHr); 467 pw.print("/hr)"); 468 pw.println(); 469 } 470 } 471 472 private final KeyguardUpdateMonitorCallback mKeyguardCallback = 473 new KeyguardUpdateMonitorCallback() { 474 @Override 475 public void onEmergencyCallAction() { 476 traceEmergencyCall(); 477 } 478 479 @Override 480 public void onKeyguardBouncerFullyShowingChanged(boolean fullyShowing) { 481 traceKeyguardBouncerChanged(fullyShowing); 482 } 483 484 @Override 485 public void onStartedWakingUp() { 486 traceScreenOn(); 487 } 488 489 @Override 490 public void onFinishedGoingToSleep(int why) { 491 traceScreenOff(why); 492 } 493 494 @Override 495 public void onKeyguardVisibilityChanged(boolean visible) { 496 traceKeyguard(visible); 497 } 498 }; 499 500 /** 501 * Converts the reason (integer) to a user-readable string 502 */ reasonToString(@eason int pulseReason)503 public static String reasonToString(@Reason int pulseReason) { 504 switch (pulseReason) { 505 case PULSE_REASON_INTENT: return "intent"; 506 case PULSE_REASON_NOTIFICATION: return "notification"; 507 case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion"; 508 case REASON_SENSOR_PICKUP: return "pickup"; 509 case REASON_SENSOR_DOUBLE_TAP: return "doubletap"; 510 case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress"; 511 case PULSE_REASON_DOCKING: return "docking"; 512 case PULSE_REASON_SENSOR_WAKE_REACH: return "reach-wakelockscreen"; 513 case REASON_SENSOR_WAKE_UP_PRESENCE: return "presence-wakeup"; 514 case REASON_SENSOR_TAP: return "tap"; 515 case REASON_SENSOR_UDFPS_LONG_PRESS: return "udfps"; 516 case REASON_SENSOR_QUICK_PICKUP: return "quickPickup"; 517 default: throw new IllegalArgumentException("invalid reason: " + pulseReason); 518 } 519 } 520 521 /** 522 * Converts {@link Reason} to {@link PowerManager.WakeReason}. 523 */ getPowerManagerWakeReason(@eason int wakeReason)524 public static @PowerManager.WakeReason int getPowerManagerWakeReason(@Reason int wakeReason) { 525 switch (wakeReason) { 526 case REASON_SENSOR_DOUBLE_TAP: 527 case REASON_SENSOR_TAP: 528 return WAKE_REASON_TAP; 529 case REASON_SENSOR_PICKUP: 530 return WAKE_REASON_LIFT; 531 case REASON_SENSOR_UDFPS_LONG_PRESS: 532 return WAKE_REASON_BIOMETRIC; 533 case PULSE_REASON_DOCKING: 534 return WAKE_REASON_PLUGGED_IN; 535 default: 536 return WAKE_REASON_GESTURE; 537 } 538 } 539 540 @Retention(RetentionPolicy.SOURCE) 541 @IntDef({PULSE_REASON_NONE, PULSE_REASON_INTENT, PULSE_REASON_NOTIFICATION, 542 PULSE_REASON_SENSOR_SIGMOTION, REASON_SENSOR_PICKUP, REASON_SENSOR_DOUBLE_TAP, 543 PULSE_REASON_SENSOR_LONG_PRESS, PULSE_REASON_DOCKING, REASON_SENSOR_WAKE_UP_PRESENCE, 544 PULSE_REASON_SENSOR_WAKE_REACH, REASON_SENSOR_TAP, 545 REASON_SENSOR_UDFPS_LONG_PRESS, REASON_SENSOR_QUICK_PICKUP}) 546 public @interface Reason {} 547 public static final int PULSE_REASON_NONE = -1; 548 public static final int PULSE_REASON_INTENT = 0; 549 public static final int PULSE_REASON_NOTIFICATION = 1; 550 public static final int PULSE_REASON_SENSOR_SIGMOTION = 2; 551 public static final int REASON_SENSOR_PICKUP = 3; 552 public static final int REASON_SENSOR_DOUBLE_TAP = 4; 553 public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5; 554 public static final int PULSE_REASON_DOCKING = 6; 555 public static final int REASON_SENSOR_WAKE_UP_PRESENCE = 7; 556 public static final int PULSE_REASON_SENSOR_WAKE_REACH = 8; 557 public static final int REASON_SENSOR_TAP = 9; 558 public static final int REASON_SENSOR_UDFPS_LONG_PRESS = 10; 559 public static final int REASON_SENSOR_QUICK_PICKUP = 11; 560 561 public static final int TOTAL_REASONS = 12; 562 } 563