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