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