• 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 = 5;
39 
40     public static final int PULSE_REASON_INTENT = 0;
41     public static final int PULSE_REASON_NOTIFICATION = 1;
42     public static final int PULSE_REASON_SENSOR_SIGMOTION = 2;
43     public static final int PULSE_REASON_SENSOR_PICKUP = 3;
44     public static final int PULSE_REASON_SENSOR_DOUBLE_TAP = 4;
45 
46     private static long[] sTimes;
47     private static String[] sMessages;
48     private static int sPosition;
49     private static int sCount;
50     private static boolean sPulsing;
51 
52     private static long sSince;
53     private static SummaryStats sPickupPulseNearVibrationStats;
54     private static SummaryStats sPickupPulseNotNearVibrationStats;
55     private static SummaryStats sNotificationPulseStats;
56     private static SummaryStats sScreenOnPulsingStats;
57     private static SummaryStats sScreenOnNotPulsingStats;
58     private static SummaryStats sEmergencyCallStats;
59     private static SummaryStats[][] sProxStats; // [reason][near/far]
60 
tracePickupPulse(Context context, boolean withinVibrationThreshold)61     public static void tracePickupPulse(Context context, boolean withinVibrationThreshold) {
62         if (!ENABLED) return;
63         init(context);
64         log("pickupPulse withinVibrationThreshold=" + withinVibrationThreshold);
65         (withinVibrationThreshold ? sPickupPulseNearVibrationStats
66                 : sPickupPulseNotNearVibrationStats).append();
67     }
68 
tracePulseStart(int reason)69     public static void tracePulseStart(int reason) {
70         if (!ENABLED) return;
71         sPulsing = true;
72         log("pulseStart reason=" + pulseReasonToString(reason));
73     }
74 
tracePulseFinish()75     public static void tracePulseFinish() {
76         if (!ENABLED) return;
77         sPulsing = false;
78         log("pulseFinish");
79     }
80 
traceNotificationPulse(Context context, long instance)81     public static void traceNotificationPulse(Context context, long instance) {
82         if (!ENABLED) return;
83         init(context);
84         log("notificationPulse instance=" + instance);
85         sNotificationPulseStats.append();
86     }
87 
init(Context context)88     private static void init(Context context) {
89         synchronized (DozeLog.class) {
90             if (sMessages == null) {
91                 sTimes = new long[SIZE];
92                 sMessages = new String[SIZE];
93                 sSince = System.currentTimeMillis();
94                 sPickupPulseNearVibrationStats = new SummaryStats();
95                 sPickupPulseNotNearVibrationStats = new SummaryStats();
96                 sNotificationPulseStats = new SummaryStats();
97                 sScreenOnPulsingStats = new SummaryStats();
98                 sScreenOnNotPulsingStats = new SummaryStats();
99                 sEmergencyCallStats = new SummaryStats();
100                 sProxStats = new SummaryStats[PULSE_REASONS][2];
101                 for (int i = 0; i < PULSE_REASONS; i++) {
102                     sProxStats[i][0] = new SummaryStats();
103                     sProxStats[i][1] = new SummaryStats();
104                 }
105                 log("init");
106                 KeyguardUpdateMonitor.getInstance(context).registerCallback(sKeyguardCallback);
107             }
108         }
109     }
110 
traceDozing(Context context, boolean dozing)111     public static void traceDozing(Context context, boolean dozing) {
112         if (!ENABLED) return;
113         sPulsing = false;
114         init(context);
115         log("dozing " + dozing);
116     }
117 
traceFling(boolean expand, boolean aboveThreshold, boolean thresholdNeeded, boolean screenOnFromTouch)118     public static void traceFling(boolean expand, boolean aboveThreshold, boolean thresholdNeeded,
119             boolean screenOnFromTouch) {
120         if (!ENABLED) return;
121         log("fling expand=" + expand + " aboveThreshold=" + aboveThreshold + " thresholdNeeded="
122                 + thresholdNeeded + " screenOnFromTouch=" + screenOnFromTouch);
123     }
124 
traceEmergencyCall()125     public static void traceEmergencyCall() {
126         if (!ENABLED) return;
127         log("emergencyCall");
128         sEmergencyCallStats.append();
129     }
130 
traceKeyguardBouncerChanged(boolean showing)131     public static void traceKeyguardBouncerChanged(boolean showing) {
132         if (!ENABLED) return;
133         log("bouncer " + showing);
134     }
135 
traceScreenOn()136     public static void traceScreenOn() {
137         if (!ENABLED) return;
138         log("screenOn pulsing=" + sPulsing);
139         (sPulsing ? sScreenOnPulsingStats : sScreenOnNotPulsingStats).append();
140         sPulsing = false;
141     }
142 
traceScreenOff(int why)143     public static void traceScreenOff(int why) {
144         if (!ENABLED) return;
145         log("screenOff why=" + why);
146     }
147 
traceKeyguard(boolean showing)148     public static void traceKeyguard(boolean showing) {
149         if (!ENABLED) return;
150         log("keyguard " + showing);
151         if (!showing) {
152             sPulsing = false;
153         }
154     }
155 
traceProximityResult(Context context, boolean near, long millis, int pulseReason)156     public static void traceProximityResult(Context context, boolean near, long millis,
157             int pulseReason) {
158         if (!ENABLED) return;
159         init(context);
160         log("proximityResult reason=" + pulseReasonToString(pulseReason) + " near=" + near
161                 + " millis=" + millis);
162         sProxStats[pulseReason][near ? 0 : 1].append();
163     }
164 
pulseReasonToString(int pulseReason)165     public static String pulseReasonToString(int pulseReason) {
166         switch (pulseReason) {
167             case PULSE_REASON_INTENT: return "intent";
168             case PULSE_REASON_NOTIFICATION: return "notification";
169             case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion";
170             case PULSE_REASON_SENSOR_PICKUP: return "pickup";
171             case PULSE_REASON_SENSOR_DOUBLE_TAP: return "doubletap";
172             default: throw new IllegalArgumentException("bad reason: " + pulseReason);
173         }
174     }
175 
dump(PrintWriter pw)176     public static void dump(PrintWriter pw) {
177         synchronized (DozeLog.class) {
178             if (sMessages == null) return;
179             pw.println("  Doze log:");
180             final int start = (sPosition - sCount + SIZE) % SIZE;
181             for (int i = 0; i < sCount; i++) {
182                 final int j = (start + i) % SIZE;
183                 pw.print("    ");
184                 pw.print(FORMAT.format(new Date(sTimes[j])));
185                 pw.print(' ');
186                 pw.println(sMessages[j]);
187             }
188             pw.print("  Doze summary stats (for ");
189             TimeUtils.formatDuration(System.currentTimeMillis() - sSince, pw);
190             pw.println("):");
191             sPickupPulseNearVibrationStats.dump(pw, "Pickup pulse (near vibration)");
192             sPickupPulseNotNearVibrationStats.dump(pw, "Pickup pulse (not near vibration)");
193             sNotificationPulseStats.dump(pw, "Notification pulse");
194             sScreenOnPulsingStats.dump(pw, "Screen on (pulsing)");
195             sScreenOnNotPulsingStats.dump(pw, "Screen on (not pulsing)");
196             sEmergencyCallStats.dump(pw, "Emergency call");
197             for (int i = 0; i < PULSE_REASONS; i++) {
198                 final String reason = pulseReasonToString(i);
199                 sProxStats[i][0].dump(pw, "Proximity near (" + reason + ")");
200                 sProxStats[i][1].dump(pw, "Proximity far (" + reason + ")");
201             }
202         }
203     }
204 
log(String msg)205     private static void log(String msg) {
206         synchronized (DozeLog.class) {
207             if (sMessages == null) return;
208             sTimes[sPosition] = System.currentTimeMillis();
209             sMessages[sPosition] = msg;
210             sPosition = (sPosition + 1) % SIZE;
211             sCount = Math.min(sCount + 1, SIZE);
212         }
213         if (DEBUG) Log.d(TAG, msg);
214     }
215 
216     private static class SummaryStats {
217         private int mCount;
218 
append()219         public void append() {
220             mCount++;
221         }
222 
dump(PrintWriter pw, String type)223         public void dump(PrintWriter pw, String type) {
224             if (mCount == 0) return;
225             pw.print("    ");
226             pw.print(type);
227             pw.print(": n=");
228             pw.print(mCount);
229             pw.print(" (");
230             final double perHr = (double) mCount / (System.currentTimeMillis() - sSince)
231                     * 1000 * 60 * 60;
232             pw.print(perHr);
233             pw.print("/hr)");
234             pw.println();
235         }
236     }
237 
238     private static final KeyguardUpdateMonitorCallback sKeyguardCallback =
239             new KeyguardUpdateMonitorCallback() {
240         @Override
241         public void onEmergencyCallAction() {
242             traceEmergencyCall();
243         }
244 
245         @Override
246         public void onKeyguardBouncerChanged(boolean bouncer) {
247             traceKeyguardBouncerChanged(bouncer);
248         }
249 
250         @Override
251         public void onStartedWakingUp() {
252             traceScreenOn();
253         }
254 
255         @Override
256         public void onFinishedGoingToSleep(int why) {
257             traceScreenOff(why);
258         }
259 
260         @Override
261         public void onKeyguardVisibilityChanged(boolean showing) {
262             traceKeyguard(showing);
263         }
264     };
265 }
266