• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.content.Context;
20 import android.os.Build;
21 import android.util.Log;
22 import android.util.TimeUtils;
23 
24 import com.android.keyguard.KeyguardUpdateMonitor;
25 import com.android.keyguard.KeyguardUpdateMonitorCallback;
26 
27 import java.io.PrintWriter;
28 import java.text.SimpleDateFormat;
29 import java.util.Date;
30 
31 public class DozeLog {
32     private static final String TAG = "DozeLog";
33     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
34     private static final boolean ENABLED = true;
35     private static final int SIZE = Build.IS_DEBUGGABLE ? 400 : 50;
36     static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
37 
38     private static final int PULSE_REASONS = 6;
39 
40     public static final int PULSE_REASON_NONE = -1;
41     public static final int PULSE_REASON_INTENT = 0;
42     public static final int PULSE_REASON_NOTIFICATION = 1;
43     public static final int PULSE_REASON_SENSOR_SIGMOTION = 2;
44     public static final int PULSE_REASON_SENSOR_PICKUP = 3;
45     public static final int PULSE_REASON_SENSOR_DOUBLE_TAP = 4;
46     public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5;
47 
48     private static boolean sRegisterKeyguardCallback = true;
49 
50     private static long[] sTimes;
51     private static String[] sMessages;
52     private static int sPosition;
53     private static int sCount;
54     private static boolean sPulsing;
55 
56     private static long sSince;
57     private static SummaryStats sPickupPulseNearVibrationStats;
58     private static SummaryStats sPickupPulseNotNearVibrationStats;
59     private static SummaryStats sNotificationPulseStats;
60     private static SummaryStats sScreenOnPulsingStats;
61     private static SummaryStats sScreenOnNotPulsingStats;
62     private static SummaryStats sEmergencyCallStats;
63     private static SummaryStats[][] sProxStats; // [reason][near/far]
64 
tracePickupPulse(Context context, boolean withinVibrationThreshold)65     public static void tracePickupPulse(Context context, boolean withinVibrationThreshold) {
66         if (!ENABLED) return;
67         init(context);
68         log("pickupPulse withinVibrationThreshold=" + withinVibrationThreshold);
69         (withinVibrationThreshold ? sPickupPulseNearVibrationStats
70                 : sPickupPulseNotNearVibrationStats).append();
71     }
72 
tracePulseStart(int reason)73     public static void tracePulseStart(int reason) {
74         if (!ENABLED) return;
75         sPulsing = true;
76         log("pulseStart reason=" + pulseReasonToString(reason));
77     }
78 
tracePulseFinish()79     public static void tracePulseFinish() {
80         if (!ENABLED) return;
81         sPulsing = false;
82         log("pulseFinish");
83     }
84 
traceNotificationPulse(Context context)85     public static void traceNotificationPulse(Context context) {
86         if (!ENABLED) return;
87         init(context);
88         log("notificationPulse");
89         sNotificationPulseStats.append();
90     }
91 
init(Context context)92     private static void init(Context context) {
93         synchronized (DozeLog.class) {
94             if (sMessages == null) {
95                 sTimes = new long[SIZE];
96                 sMessages = new String[SIZE];
97                 sSince = System.currentTimeMillis();
98                 sPickupPulseNearVibrationStats = new SummaryStats();
99                 sPickupPulseNotNearVibrationStats = new SummaryStats();
100                 sNotificationPulseStats = new SummaryStats();
101                 sScreenOnPulsingStats = new SummaryStats();
102                 sScreenOnNotPulsingStats = new SummaryStats();
103                 sEmergencyCallStats = new SummaryStats();
104                 sProxStats = new SummaryStats[PULSE_REASONS][2];
105                 for (int i = 0; i < PULSE_REASONS; i++) {
106                     sProxStats[i][0] = new SummaryStats();
107                     sProxStats[i][1] = new SummaryStats();
108                 }
109                 log("init");
110                 if (sRegisterKeyguardCallback) {
111                     KeyguardUpdateMonitor.getInstance(context).registerCallback(sKeyguardCallback);
112                 }
113             }
114         }
115     }
116 
traceDozing(Context context, boolean dozing)117     public static void traceDozing(Context context, boolean dozing) {
118         if (!ENABLED) return;
119         sPulsing = false;
120         init(context);
121         log("dozing " + dozing);
122     }
123 
traceFling(boolean expand, boolean aboveThreshold, boolean thresholdNeeded, boolean screenOnFromTouch)124     public static void traceFling(boolean expand, boolean aboveThreshold, boolean thresholdNeeded,
125             boolean screenOnFromTouch) {
126         if (!ENABLED) return;
127         log("fling expand=" + expand + " aboveThreshold=" + aboveThreshold + " thresholdNeeded="
128                 + thresholdNeeded + " screenOnFromTouch=" + screenOnFromTouch);
129     }
130 
traceEmergencyCall()131     public static void traceEmergencyCall() {
132         if (!ENABLED) return;
133         log("emergencyCall");
134         sEmergencyCallStats.append();
135     }
136 
traceKeyguardBouncerChanged(boolean showing)137     public static void traceKeyguardBouncerChanged(boolean showing) {
138         if (!ENABLED) return;
139         log("bouncer " + showing);
140     }
141 
traceScreenOn()142     public static void traceScreenOn() {
143         if (!ENABLED) return;
144         log("screenOn pulsing=" + sPulsing);
145         (sPulsing ? sScreenOnPulsingStats : sScreenOnNotPulsingStats).append();
146         sPulsing = false;
147     }
148 
traceScreenOff(int why)149     public static void traceScreenOff(int why) {
150         if (!ENABLED) return;
151         log("screenOff why=" + why);
152     }
153 
traceMissedTick(String delay)154     public static void traceMissedTick(String delay) {
155         if (!ENABLED) return;
156         log("missedTick by=" + delay);
157     }
158 
traceKeyguard(boolean showing)159     public static void traceKeyguard(boolean showing) {
160         if (!ENABLED) return;
161         log("keyguard " + showing);
162         if (!showing) {
163             sPulsing = false;
164         }
165     }
166 
traceState(DozeMachine.State state)167     public static void traceState(DozeMachine.State state) {
168         if (!ENABLED) return;
169         log("state " + state);
170     }
171 
traceProximityResult(Context context, boolean near, long millis, int pulseReason)172     public static void traceProximityResult(Context context, boolean near, long millis,
173             int pulseReason) {
174         if (!ENABLED) return;
175         init(context);
176         log("proximityResult reason=" + pulseReasonToString(pulseReason) + " near=" + near
177                 + " millis=" + millis);
178         sProxStats[pulseReason][near ? 0 : 1].append();
179     }
180 
pulseReasonToString(int pulseReason)181     public static String pulseReasonToString(int pulseReason) {
182         switch (pulseReason) {
183             case PULSE_REASON_INTENT: return "intent";
184             case PULSE_REASON_NOTIFICATION: return "notification";
185             case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion";
186             case PULSE_REASON_SENSOR_PICKUP: return "pickup";
187             case PULSE_REASON_SENSOR_DOUBLE_TAP: return "doubletap";
188             case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress";
189             default: throw new IllegalArgumentException("bad reason: " + pulseReason);
190         }
191     }
192 
dump(PrintWriter pw)193     public static void dump(PrintWriter pw) {
194         synchronized (DozeLog.class) {
195             if (sMessages == null) return;
196             pw.println("  Doze log:");
197             final int start = (sPosition - sCount + SIZE) % SIZE;
198             for (int i = 0; i < sCount; i++) {
199                 final int j = (start + i) % SIZE;
200                 pw.print("    ");
201                 pw.print(FORMAT.format(new Date(sTimes[j])));
202                 pw.print(' ');
203                 pw.println(sMessages[j]);
204             }
205             pw.print("  Doze summary stats (for ");
206             TimeUtils.formatDuration(System.currentTimeMillis() - sSince, pw);
207             pw.println("):");
208             sPickupPulseNearVibrationStats.dump(pw, "Pickup pulse (near vibration)");
209             sPickupPulseNotNearVibrationStats.dump(pw, "Pickup pulse (not near vibration)");
210             sNotificationPulseStats.dump(pw, "Notification pulse");
211             sScreenOnPulsingStats.dump(pw, "Screen on (pulsing)");
212             sScreenOnNotPulsingStats.dump(pw, "Screen on (not pulsing)");
213             sEmergencyCallStats.dump(pw, "Emergency call");
214             for (int i = 0; i < PULSE_REASONS; i++) {
215                 final String reason = pulseReasonToString(i);
216                 sProxStats[i][0].dump(pw, "Proximity near (" + reason + ")");
217                 sProxStats[i][1].dump(pw, "Proximity far (" + reason + ")");
218             }
219         }
220     }
221 
log(String msg)222     private static void log(String msg) {
223         synchronized (DozeLog.class) {
224             if (sMessages == null) return;
225             sTimes[sPosition] = System.currentTimeMillis();
226             sMessages[sPosition] = msg;
227             sPosition = (sPosition + 1) % SIZE;
228             sCount = Math.min(sCount + 1, SIZE);
229         }
230         if (DEBUG) Log.d(TAG, msg);
231     }
232 
tracePulseDropped(Context context, boolean pulsePending, DozeMachine.State state, boolean blocked)233     public static void tracePulseDropped(Context context, boolean pulsePending,
234             DozeMachine.State state, boolean blocked) {
235         if (!ENABLED) return;
236         init(context);
237         log("pulseDropped pulsePending=" + pulsePending + " state="
238                 + state + " blocked=" + blocked);
239     }
240 
tracePulseTouchDisabledByProx(Context context, boolean disabled)241     public static void tracePulseTouchDisabledByProx(Context context, boolean disabled) {
242         if (!ENABLED) return;
243         init(context);
244         log("pulseTouchDisabledByProx " + disabled);
245     }
246 
setRegisterKeyguardCallback(boolean registerKeyguardCallback)247     public static void setRegisterKeyguardCallback(boolean registerKeyguardCallback) {
248         if (!ENABLED) return;
249         synchronized (DozeLog.class) {
250             if (sRegisterKeyguardCallback != registerKeyguardCallback && sMessages != null) {
251                 throw new IllegalStateException("Cannot change setRegisterKeyguardCallback "
252                         + "after init()");
253             }
254             sRegisterKeyguardCallback = registerKeyguardCallback;
255         }
256     }
257 
traceSensor(Context context, int pulseReason)258     public static void traceSensor(Context context, int pulseReason) {
259         if (!ENABLED) return;
260         init(context);
261         log("sensor type=" + pulseReasonToString(pulseReason));
262     }
263 
264     private static class SummaryStats {
265         private int mCount;
266 
append()267         public void append() {
268             mCount++;
269         }
270 
dump(PrintWriter pw, String type)271         public void dump(PrintWriter pw, String type) {
272             if (mCount == 0) return;
273             pw.print("    ");
274             pw.print(type);
275             pw.print(": n=");
276             pw.print(mCount);
277             pw.print(" (");
278             final double perHr = (double) mCount / (System.currentTimeMillis() - sSince)
279                     * 1000 * 60 * 60;
280             pw.print(perHr);
281             pw.print("/hr)");
282             pw.println();
283         }
284     }
285 
286     private static final KeyguardUpdateMonitorCallback sKeyguardCallback =
287             new KeyguardUpdateMonitorCallback() {
288         @Override
289         public void onEmergencyCallAction() {
290             traceEmergencyCall();
291         }
292 
293         @Override
294         public void onKeyguardBouncerChanged(boolean bouncer) {
295             traceKeyguardBouncerChanged(bouncer);
296         }
297 
298         @Override
299         public void onStartedWakingUp() {
300             traceScreenOn();
301         }
302 
303         @Override
304         public void onFinishedGoingToSleep(int why) {
305             traceScreenOff(why);
306         }
307 
308         @Override
309         public void onKeyguardVisibilityChanged(boolean showing) {
310             traceKeyguard(showing);
311         }
312     };
313 }
314