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 android.annotation.IntDef; 20 import android.util.TimeUtils; 21 22 import androidx.annotation.NonNull; 23 24 import com.android.keyguard.KeyguardUpdateMonitor; 25 import com.android.keyguard.KeyguardUpdateMonitorCallback; 26 import com.android.systemui.Dumpable; 27 import com.android.systemui.dagger.SysUISingleton; 28 import com.android.systemui.dump.DumpManager; 29 import com.android.systemui.statusbar.policy.DevicePostureController; 30 31 import java.io.FileDescriptor; 32 import java.io.PrintWriter; 33 import java.lang.annotation.Retention; 34 import java.lang.annotation.RetentionPolicy; 35 36 import javax.inject.Inject; 37 38 /** 39 * Logs doze events for debugging and triaging purposes. Logs are dumped in bugreports or on demand: 40 * adb shell dumpsys activity service com.android.systemui/.SystemUIService \ 41 * dependency DumpController DozeLog,DozeStats 42 */ 43 @SysUISingleton 44 public class DozeLog implements Dumpable { 45 private final DozeLogger mLogger; 46 47 private boolean mPulsing; 48 private long mSince; 49 private SummaryStats mPickupPulseNearVibrationStats; 50 private SummaryStats mPickupPulseNotNearVibrationStats; 51 private SummaryStats mNotificationPulseStats; 52 private SummaryStats mScreenOnPulsingStats; 53 private SummaryStats mScreenOnNotPulsingStats; 54 private SummaryStats mEmergencyCallStats; 55 private SummaryStats[][] mProxStats; // [reason][near/far] 56 57 @Inject DozeLog( KeyguardUpdateMonitor keyguardUpdateMonitor, DumpManager dumpManager, DozeLogger logger)58 public DozeLog( 59 KeyguardUpdateMonitor keyguardUpdateMonitor, 60 DumpManager dumpManager, 61 DozeLogger logger) { 62 mLogger = logger; 63 mSince = System.currentTimeMillis(); 64 mPickupPulseNearVibrationStats = new SummaryStats(); 65 mPickupPulseNotNearVibrationStats = new SummaryStats(); 66 mNotificationPulseStats = new SummaryStats(); 67 mScreenOnPulsingStats = new SummaryStats(); 68 mScreenOnNotPulsingStats = new SummaryStats(); 69 mEmergencyCallStats = new SummaryStats(); 70 mProxStats = new SummaryStats[TOTAL_REASONS][2]; 71 for (int i = 0; i < TOTAL_REASONS; i++) { 72 mProxStats[i][0] = new SummaryStats(); 73 mProxStats[i][1] = new SummaryStats(); 74 } 75 76 if (keyguardUpdateMonitor != null) { 77 keyguardUpdateMonitor.registerCallback(mKeyguardCallback); 78 } 79 80 dumpManager.registerDumpable("DumpStats", this); 81 } 82 83 /** 84 * Appends pickup wakeup event to the logs 85 */ tracePickupWakeUp(boolean withinVibrationThreshold)86 public void tracePickupWakeUp(boolean withinVibrationThreshold) { 87 mLogger.logPickupWakeup(withinVibrationThreshold); 88 (withinVibrationThreshold ? mPickupPulseNearVibrationStats 89 : mPickupPulseNotNearVibrationStats).append(); 90 } 91 92 /** 93 * Appends pulse started event to the logs. 94 * @param reason why the pulse started 95 */ tracePulseStart(@eason int reason)96 public void tracePulseStart(@Reason int reason) { 97 mLogger.logPulseStart(reason); 98 mPulsing = true; 99 } 100 101 /** 102 * Appends pulse finished event to the logs 103 */ tracePulseFinish()104 public void tracePulseFinish() { 105 mLogger.logPulseFinish(); 106 mPulsing = false; 107 } 108 109 /** 110 * Appends pulse event to the logs 111 */ traceNotificationPulse()112 public void traceNotificationPulse() { 113 mLogger.logNotificationPulse(); 114 mNotificationPulseStats.append(); 115 } 116 117 /** 118 * Appends dozing event to the logs. Logs current dozing state when entering/exiting AOD. 119 * @param dozing true if dozing, else false 120 */ traceDozing(boolean dozing)121 public void traceDozing(boolean dozing) { 122 mLogger.logDozing(dozing); 123 mPulsing = false; 124 } 125 126 /** 127 * Appends dozing event to the logs when dozing has changed in AOD. 128 * @param dozing true if we're now dozing, else false 129 */ traceDozingChanged(boolean dozing)130 public void traceDozingChanged(boolean dozing) { 131 mLogger.logDozingChanged(dozing); 132 } 133 134 /** 135 * Appends dozing event to the logs 136 * @param suppressed true if dozing is suppressed 137 */ traceDozingSuppressed(boolean suppressed)138 public void traceDozingSuppressed(boolean suppressed) { 139 mLogger.logDozingSuppressed(suppressed); 140 } 141 142 /** 143 * Appends fling event to the logs 144 */ traceFling(boolean expand, boolean aboveThreshold, boolean thresholdNeeded, boolean screenOnFromTouch)145 public void traceFling(boolean expand, boolean aboveThreshold, boolean thresholdNeeded, 146 boolean screenOnFromTouch) { 147 mLogger.logFling(expand, aboveThreshold, thresholdNeeded, screenOnFromTouch); 148 } 149 150 /** 151 * Appends emergency call event to the logs 152 */ traceEmergencyCall()153 public void traceEmergencyCall() { 154 mLogger.logEmergencyCall(); 155 mEmergencyCallStats.append(); 156 } 157 158 /** 159 * Appends keyguard bouncer changed event to the logs 160 * @param showing true if the keyguard bouncer is showing, else false 161 */ traceKeyguardBouncerChanged(boolean showing)162 public void traceKeyguardBouncerChanged(boolean showing) { 163 mLogger.logKeyguardBouncerChanged(showing); 164 } 165 166 /** 167 * Appends screen-on event to the logs 168 */ traceScreenOn()169 public void traceScreenOn() { 170 mLogger.logScreenOn(mPulsing); 171 (mPulsing ? mScreenOnPulsingStats : mScreenOnNotPulsingStats).append(); 172 mPulsing = false; 173 } 174 175 /** 176 * Appends screen-off event to the logs 177 * @param why reason the screen is off 178 */ traceScreenOff(int why)179 public void traceScreenOff(int why) { 180 mLogger.logScreenOff(why); 181 } 182 183 /** 184 * Appends missed tick event to the logs 185 * @param delay of the missed tick 186 */ traceMissedTick(String delay)187 public void traceMissedTick(String delay) { 188 mLogger.logMissedTick(delay); 189 } 190 191 /** 192 * Appends time tick scheduled event to the logs 193 * @param when time tick scheduled at 194 * @param triggerAt time tick trigger at 195 */ traceTimeTickScheduled(long when, long triggerAt)196 public void traceTimeTickScheduled(long when, long triggerAt) { 197 mLogger.logTimeTickScheduled(when, triggerAt); 198 } 199 200 /** 201 * Appends keyguard visibility change event to the logs 202 * @param showing whether the keyguard is now showing 203 */ traceKeyguard(boolean showing)204 public void traceKeyguard(boolean showing) { 205 mLogger.logKeyguardVisibilityChange(showing); 206 if (!showing) mPulsing = false; 207 } 208 209 /** 210 * Appends doze state changed event to the logs 211 * @param state new DozeMachine state 212 */ traceState(DozeMachine.State state)213 public void traceState(DozeMachine.State state) { 214 mLogger.logDozeStateChanged(state); 215 } 216 217 /** 218 * Appends doze state changed sent to all DozeMachine parts event to the logs 219 * @param state new DozeMachine state 220 */ traceDozeStateSendComplete(DozeMachine.State state)221 public void traceDozeStateSendComplete(DozeMachine.State state) { 222 mLogger.logStateChangedSent(state); 223 } 224 225 /** 226 * Appends display state delayed by UDFPS event to the logs 227 * @param delayedDisplayState the display screen state that was delayed 228 */ traceDisplayStateDelayedByUdfps(int delayedDisplayState)229 public void traceDisplayStateDelayedByUdfps(int delayedDisplayState) { 230 mLogger.logDisplayStateDelayedByUdfps(delayedDisplayState); 231 } 232 233 /** 234 * Appends display state changed event to the logs 235 * @param displayState new DozeMachine state 236 */ traceDisplayState(int displayState)237 public void traceDisplayState(int displayState) { 238 mLogger.logDisplayStateChanged(displayState); 239 } 240 241 /** 242 * Appends wake-display event to the logs. 243 * @param wake if we're waking up or sleeping. 244 */ traceWakeDisplay(boolean wake, @Reason int reason)245 public void traceWakeDisplay(boolean wake, @Reason int reason) { 246 mLogger.logWakeDisplay(wake, reason); 247 } 248 249 /** 250 * Appends proximity result event to the logs 251 * @param near true if near, else false 252 * @param reason why proximity result was triggered 253 */ traceProximityResult(boolean near, long millis, @Reason int reason)254 public void traceProximityResult(boolean near, long millis, @Reason int reason) { 255 mLogger.logProximityResult(near, millis, reason); 256 mProxStats[reason][near ? 0 : 1].append(); 257 } 258 259 @Override dump(@onNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args)260 public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { 261 synchronized (DozeLog.class) { 262 pw.print(" Doze summary stats (for "); 263 TimeUtils.formatDuration(System.currentTimeMillis() - mSince, pw); 264 pw.println("):"); 265 mPickupPulseNearVibrationStats.dump(pw, "Pickup pulse (near vibration)"); 266 mPickupPulseNotNearVibrationStats.dump(pw, "Pickup pulse (not near vibration)"); 267 mNotificationPulseStats.dump(pw, "Notification pulse"); 268 mScreenOnPulsingStats.dump(pw, "Screen on (pulsing)"); 269 mScreenOnNotPulsingStats.dump(pw, "Screen on (not pulsing)"); 270 mEmergencyCallStats.dump(pw, "Emergency call"); 271 for (int i = 0; i < TOTAL_REASONS; i++) { 272 final String reason = reasonToString(i); 273 mProxStats[i][0].dump(pw, "Proximity near (" + reason + ")"); 274 mProxStats[i][1].dump(pw, "Proximity far (" + reason + ")"); 275 } 276 } 277 } 278 279 /** 280 * Appends doze updates due to a posture change. 281 */ tracePostureChanged( @evicePostureController.DevicePostureInt int posture, String partUpdated )282 public void tracePostureChanged( 283 @DevicePostureController.DevicePostureInt int posture, 284 String partUpdated 285 ) { 286 mLogger.logPostureChanged(posture, partUpdated); 287 } 288 289 /** 290 * Appends pulse dropped event to logs 291 */ tracePulseDropped(boolean pulsePending, DozeMachine.State state, boolean blocked)292 public void tracePulseDropped(boolean pulsePending, DozeMachine.State state, boolean blocked) { 293 mLogger.logPulseDropped(pulsePending, state, blocked); 294 } 295 296 /** 297 * Appends sensor event dropped event to logs 298 */ traceSensorEventDropped(int sensorEvent, String reason)299 public void traceSensorEventDropped(int sensorEvent, String reason) { 300 mLogger.logSensorEventDropped(sensorEvent, reason); 301 } 302 303 /** 304 * Appends pulse dropped event to logs 305 * @param reason why the pulse was dropped 306 */ tracePulseDropped(String reason)307 public void tracePulseDropped(String reason) { 308 mLogger.logPulseDropped(reason); 309 } 310 311 /** 312 * Appends pulse touch displayed by prox sensor event to logs 313 * @param disabled 314 */ tracePulseTouchDisabledByProx(boolean disabled)315 public void tracePulseTouchDisabledByProx(boolean disabled) { 316 mLogger.logPulseTouchDisabledByProx(disabled); 317 } 318 319 /** 320 * Appends sensor triggered event to logs 321 * @param reason why the sensor was triggered 322 */ traceSensor(@eason int reason)323 public void traceSensor(@Reason int reason) { 324 mLogger.logSensorTriggered(reason); 325 } 326 327 /** 328 * Appends doze suppressed event to the logs 329 * @param suppressedState The {@link DozeMachine.State} that was suppressed 330 */ traceDozeSuppressed(DozeMachine.State suppressedState)331 public void traceDozeSuppressed(DozeMachine.State suppressedState) { 332 mLogger.logDozeSuppressed(suppressedState); 333 } 334 335 /** 336 * Appends new AOD sreen brightness to logs 337 * @param brightness display brightness setting 338 */ traceDozeScreenBrightness(int brightness)339 public void traceDozeScreenBrightness(int brightness) { 340 mLogger.logDozeScreenBrightness(brightness); 341 } 342 343 /** 344 * Appends new AOD dimming scrim opacity to logs 345 * @param scrimOpacity 346 */ traceSetAodDimmingScrim(float scrimOpacity)347 public void traceSetAodDimmingScrim(float scrimOpacity) { 348 mLogger.logSetAodDimmingScrim((long) scrimOpacity); 349 } 350 351 private class SummaryStats { 352 private int mCount; 353 append()354 public void append() { 355 mCount++; 356 } 357 dump(PrintWriter pw, String type)358 public void dump(PrintWriter pw, String type) { 359 if (mCount == 0) return; 360 pw.print(" "); 361 pw.print(type); 362 pw.print(": n="); 363 pw.print(mCount); 364 pw.print(" ("); 365 final double perHr = (double) mCount / (System.currentTimeMillis() - mSince) 366 * 1000 * 60 * 60; 367 pw.print(perHr); 368 pw.print("/hr)"); 369 pw.println(); 370 } 371 } 372 373 private final KeyguardUpdateMonitorCallback mKeyguardCallback = 374 new KeyguardUpdateMonitorCallback() { 375 @Override 376 public void onEmergencyCallAction() { 377 traceEmergencyCall(); 378 } 379 380 @Override 381 public void onKeyguardBouncerChanged(boolean bouncer) { 382 traceKeyguardBouncerChanged(bouncer); 383 } 384 385 @Override 386 public void onStartedWakingUp() { 387 traceScreenOn(); 388 } 389 390 @Override 391 public void onFinishedGoingToSleep(int why) { 392 traceScreenOff(why); 393 } 394 395 @Override 396 public void onKeyguardVisibilityChanged(boolean showing) { 397 traceKeyguard(showing); 398 } 399 }; 400 401 /** 402 * Converts the reason (integer) to a user-readable string 403 */ reasonToString(@eason int pulseReason)404 public static String reasonToString(@Reason int pulseReason) { 405 switch (pulseReason) { 406 case PULSE_REASON_INTENT: return "intent"; 407 case PULSE_REASON_NOTIFICATION: return "notification"; 408 case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion"; 409 case REASON_SENSOR_PICKUP: return "pickup"; 410 case REASON_SENSOR_DOUBLE_TAP: return "doubletap"; 411 case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress"; 412 case PULSE_REASON_DOCKING: return "docking"; 413 case PULSE_REASON_SENSOR_WAKE_REACH: return "reach-wakelockscreen"; 414 case REASON_SENSOR_WAKE_UP_PRESENCE: return "presence-wakeup"; 415 case REASON_SENSOR_TAP: return "tap"; 416 case REASON_SENSOR_UDFPS_LONG_PRESS: return "udfps"; 417 case REASON_SENSOR_QUICK_PICKUP: return "quickPickup"; 418 default: throw new IllegalArgumentException("invalid reason: " + pulseReason); 419 } 420 } 421 422 @Retention(RetentionPolicy.SOURCE) 423 @IntDef({PULSE_REASON_NONE, PULSE_REASON_INTENT, PULSE_REASON_NOTIFICATION, 424 PULSE_REASON_SENSOR_SIGMOTION, REASON_SENSOR_PICKUP, REASON_SENSOR_DOUBLE_TAP, 425 PULSE_REASON_SENSOR_LONG_PRESS, PULSE_REASON_DOCKING, REASON_SENSOR_WAKE_UP_PRESENCE, 426 PULSE_REASON_SENSOR_WAKE_REACH, REASON_SENSOR_TAP, 427 REASON_SENSOR_UDFPS_LONG_PRESS, REASON_SENSOR_QUICK_PICKUP}) 428 public @interface Reason {} 429 public static final int PULSE_REASON_NONE = -1; 430 public static final int PULSE_REASON_INTENT = 0; 431 public static final int PULSE_REASON_NOTIFICATION = 1; 432 public static final int PULSE_REASON_SENSOR_SIGMOTION = 2; 433 public static final int REASON_SENSOR_PICKUP = 3; 434 public static final int REASON_SENSOR_DOUBLE_TAP = 4; 435 public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5; 436 public static final int PULSE_REASON_DOCKING = 6; 437 public static final int REASON_SENSOR_WAKE_UP_PRESENCE = 7; 438 public static final int PULSE_REASON_SENSOR_WAKE_REACH = 8; 439 public static final int REASON_SENSOR_TAP = 9; 440 public static final int REASON_SENSOR_UDFPS_LONG_PRESS = 10; 441 public static final int REASON_SENSOR_QUICK_PICKUP = 11; 442 443 public static final int TOTAL_REASONS = 12; 444 } 445