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