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