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