summaryrefslogtreecommitdiffstats
path: root/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
blob: 7eb9c6eaec6a170c82c36b860b3b37bf9dd3f41a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */

package com.android.systemui.doze;

import android.content.Context;
import android.os.Build;
import android.util.Log;
import android.util.TimeUtils;

import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;

import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DozeLog {
    private static final String TAG = "DozeLog";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
    private static final boolean ENABLED = true;
    private static final int SIZE = Build.IS_DEBUGGABLE ? 400 : 50;
    private static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");

    private static final int PULSE_REASONS = 4;

    public static final int PULSE_REASON_INTENT = 0;
    public static final int PULSE_REASON_NOTIFICATION = 1;
    public static final int PULSE_REASON_SENSOR_SIGMOTION = 2;
    public static final int PULSE_REASON_SENSOR_PICKUP = 3;

    private static long[] sTimes;
    private static String[] sMessages;
    private static int sPosition;
    private static int sCount;
    private static boolean sPulsing;

    private static long sSince;
    private static SummaryStats sPickupPulseNearVibrationStats;
    private static SummaryStats sPickupPulseNotNearVibrationStats;
    private static SummaryStats sNotificationPulseStats;
    private static SummaryStats sScreenOnPulsingStats;
    private static SummaryStats sScreenOnNotPulsingStats;
    private static SummaryStats sEmergencyCallStats;
    private static SummaryStats[][] sProxStats; // [reason][near/far]

    public static void tracePickupPulse(boolean withinVibrationThreshold) {
        if (!ENABLED) return;
        log("pickupPulse withinVibrationThreshold=" + withinVibrationThreshold);
        (withinVibrationThreshold ? sPickupPulseNearVibrationStats
                : sPickupPulseNotNearVibrationStats).append();
    }

    public static void tracePulseStart(int reason) {
        if (!ENABLED) return;
        sPulsing = true;
        log("pulseStart reason=" + pulseReasonToString(reason));
    }

    public static void tracePulseFinish() {
        if (!ENABLED) return;
        sPulsing = false;
        log("pulseFinish");
    }

    public static void traceNotificationPulse(long instance) {
        if (!ENABLED) return;
        log("notificationPulse instance=" + instance);
        sNotificationPulseStats.append();
    }

    public static void traceDozing(Context context, boolean dozing) {
        if (!ENABLED) return;
        sPulsing = false;
        synchronized (DozeLog.class) {
            if (dozing && sMessages == null) {
                sTimes = new long[SIZE];
                sMessages = new String[SIZE];
                sSince = System.currentTimeMillis();
                sPickupPulseNearVibrationStats = new SummaryStats();
                sPickupPulseNotNearVibrationStats = new SummaryStats();
                sNotificationPulseStats = new SummaryStats();
                sScreenOnPulsingStats = new SummaryStats();
                sScreenOnNotPulsingStats = new SummaryStats();
                sEmergencyCallStats = new SummaryStats();
                sProxStats = new SummaryStats[PULSE_REASONS][2];
                for (int i = 0; i < PULSE_REASONS; i++) {
                    sProxStats[i][0] = new SummaryStats();
                    sProxStats[i][1] = new SummaryStats();
                }
                log("init");
                KeyguardUpdateMonitor.getInstance(context).registerCallback(sKeyguardCallback);
            }
        }
        log("dozing " + dozing);
    }

    public static void traceFling(boolean expand, boolean aboveThreshold, boolean thresholdNeeded,
            boolean screenOnFromTouch) {
        if (!ENABLED) return;
        log("fling expand=" + expand + " aboveThreshold=" + aboveThreshold + " thresholdNeeded="
                + thresholdNeeded + " screenOnFromTouch=" + screenOnFromTouch);
    }

    public static void traceEmergencyCall() {
        if (!ENABLED) return;
        log("emergencyCall");
        sEmergencyCallStats.append();
    }

    public static void traceKeyguardBouncerChanged(boolean showing) {
        if (!ENABLED) return;
        log("bouncer " + showing);
    }

    public static void traceScreenOn() {
        if (!ENABLED) return;
        log("screenOn pulsing=" + sPulsing);
        (sPulsing ? sScreenOnPulsingStats : sScreenOnNotPulsingStats).append();
        sPulsing = false;
    }

    public static void traceScreenOff(int why) {
        if (!ENABLED) return;
        log("screenOff why=" + why);
    }

    public static void traceKeyguard(boolean showing) {
        if (!ENABLED) return;
        log("keyguard " + showing);
        if (!showing) {
            sPulsing = false;
        }
    }

    public static void traceProximityResult(boolean near, long millis, int pulseReason) {
        if (!ENABLED) return;
        log("proximityResult reason=" + pulseReasonToString(pulseReason) + " near=" + near
                + " millis=" + millis);
        sProxStats[pulseReason][near ? 0 : 1].append();
    }

    private static String pulseReasonToString(int pulseReason) {
        switch (pulseReason) {
            case PULSE_REASON_INTENT: return "intent";
            case PULSE_REASON_NOTIFICATION: return "notification";
            case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion";
            case PULSE_REASON_SENSOR_PICKUP: return "pickup";
            default: throw new IllegalArgumentException("bad reason: " + pulseReason);
        }
    }

    public static void dump(PrintWriter pw) {
        synchronized (DozeLog.class) {
            if (sMessages == null) return;
            pw.println("  Doze log:");
            final int start = (sPosition - sCount + SIZE) % SIZE;
            for (int i = 0; i < sCount; i++) {
                final int j = (start + i) % SIZE;
                pw.print("    ");
                pw.print(FORMAT.format(new Date(sTimes[j])));
                pw.print(' ');
                pw.println(sMessages[j]);
            }
            pw.print("  Doze summary stats (for ");
            TimeUtils.formatDuration(System.currentTimeMillis() - sSince, pw);
            pw.println("):");
            sPickupPulseNearVibrationStats.dump(pw, "Pickup pulse (near vibration)");
            sPickupPulseNotNearVibrationStats.dump(pw, "Pickup pulse (not near vibration)");
            sNotificationPulseStats.dump(pw, "Notification pulse");
            sScreenOnPulsingStats.dump(pw, "Screen on (pulsing)");
            sScreenOnNotPulsingStats.dump(pw, "Screen on (not pulsing)");
            sEmergencyCallStats.dump(pw, "Emergency call");
            for (int i = 0; i < PULSE_REASONS; i++) {
                final String reason = pulseReasonToString(i);
                sProxStats[i][0].dump(pw, "Proximity near (" + reason + ")");
                sProxStats[i][1].dump(pw, "Proximity far (" + reason + ")");
            }
        }
    }

    private static void log(String msg) {
        synchronized (DozeLog.class) {
            if (sMessages == null) return;
            sTimes[sPosition] = System.currentTimeMillis();
            sMessages[sPosition] = msg;
            sPosition = (sPosition + 1) % SIZE;
            sCount = Math.min(sCount + 1, SIZE);
        }
        if (DEBUG) Log.d(TAG, msg);
    }

    private static class SummaryStats {
        private int mCount;

        public void append() {
            mCount++;
        }

        public void dump(PrintWriter pw, String type) {
            if (mCount == 0) return;
            pw.print("    ");
            pw.print(type);
            pw.print(": n=");
            pw.print(mCount);
            pw.print(" (");
            final double perHr = (double) mCount / (System.currentTimeMillis() - sSince)
                    * 1000 * 60 * 60;
            pw.print(perHr);
            pw.print("/hr)");
            pw.println();
        }
    }

    private static final KeyguardUpdateMonitorCallback sKeyguardCallback =
            new KeyguardUpdateMonitorCallback() {
        @Override
        public void onEmergencyCallAction() {
            traceEmergencyCall();
        }

        @Override
        public void onKeyguardBouncerChanged(boolean bouncer) {
            traceKeyguardBouncerChanged(bouncer);
        }

        @Override
        public void onScreenTurnedOn() {
            traceScreenOn();
        }

        @Override
        public void onScreenTurnedOff(int why) {
            traceScreenOff(why);
        }

        @Override
        public void onKeyguardVisibilityChanged(boolean showing) {
            traceKeyguard(showing);
        }
    };
}