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